惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw 第07章:参数化表达式与Spreadsheet 第08章:装配设计Assembly 第06章:Part工作台与几何内核 第05章:PartDesign实体特征建模 第04章:草图Sketcher约束建模 第02章:安装版本与工作环境配置 第03章:界面工作台与基础操作 第01章:项目全景与学习路线 第十二章:插件开发、研究功能与最佳实践 第十章:定时任务与自动化(Cron) 第七章:技能、记忆与自学习闭环 第八章:MCP 集成与上下文文件 第六章:工具系统与终端后端 第五章:模型供应商与配置体系 Hermes Agent 教程目录 第十一章:语音、视觉、浏览器与子代理协作 第四章:CLI/TUI 与会话管理 第十二章:学习路线、实战方案与最佳实践 第十一章:源码结构、开发调试与插件开发 第十章:自动化、远程访问、日志与排障 第九章:Control UI、节点、Canvas 与语音能力 第七章:工具、技能、插件与能力扩展 第八章:安全模型、访问控制与沙箱实践 第六章:Agent 工作区、会话与多智能体路由 第五章:多通道消息接入与聊天平台配置 第四章:配置体系、模型接入与认证管理 第三章:Gateway 架构、协议与运行机制 第二章:安装、环境准备与快速上手 第一章:OpenClaw 项目概览与核心定位 oh-my-openagent 教程目录 09-命令模型回退与配置参考 10-实战案例最佳实践与故障排除 05-工作模式-Ultrawork-Prometheus-Atlas 08-Hooks与MCP系统 06-Category与Skill系统 07-核心工具链 04-智能体全景详解 03-安装与环境配置 02-整体架构与多模型编排机制 01-项目简介与核心理念 01-项目概览与学习路线 02-安装部署与工具适配 03-Skill机制与using-superpowers 05-TDD系统化调试与完成前验证 04-需求澄清方案设计与计划编写 07-并行智能体子智能体与Git-Worktree 第六章:代码审查、反馈处理与分支收尾 08-中国特色Skills与本土团队落地 09-MCP构建工作流执行与自定义Skill 第23章:FreeCAD-Python-API Clipper2 C# 源码解读教程 第19章:PolyTree 多边形树结构 第20章:实际应用与最佳实践 第18章:Minkowski 和与差 第17章:RectClip 矩形裁剪优化 第16章:ClipperOffset 偏移类详解 第15章:填充规则详解 第14章:布尔运算执行流程 第13章:ClipperD 浮点裁剪类 第11章:OutRec 与 OutPt 输出结构 第9章:Active 活动边结构 第10章:Vertex 顶点与 LocalMinima 局部极小值 第12章:Clipper64 裁剪类详解 第7章:高精度运算与128位整数 第8章:ClipperBase 基类详解 第5章:枚举类型与常量定义 第6章:InternalClipper 内部工具类 第2章:核心数据结构 - Point64、PointD 第3章:路径与多边形表示 - Path64、PathD、Paths64、PathsD 第4章:矩形边界 - Rect64、RectD
第二章:快速开始指南
我才是银古 · 2026-06-22 · via 博客园 - 我才是银古

第二章:快速开始指南

2.1 环境准备

2.1.1 前提条件

在开始使用 geometry-api-net 之前,请确保您的开发环境满足以下条件:

  • .NET SDK:8.0 或更高版本(推荐使用最新 LTS 版本)
  • IDE:Visual Studio 2022、VS Code 或 JetBrains Rider
  • 操作系统:Windows、macOS 或 Linux

2.1.2 验证 .NET SDK 安装

打开终端或命令提示符,运行以下命令验证 .NET SDK 是否正确安装:

dotnet --version

预期输出类似于:

8.0.100

2.1.3 获取源代码

geometry-api-net 目前托管在 GitHub 上,可以通过以下方式获取:

# 克隆仓库
git clone https://github.com/znlgis/geometry-api-net.git

# 进入项目目录
cd geometry-api-net

2.2 构建项目

2.2.1 还原依赖项

# 还原所有项目的依赖项
dotnet restore

2.2.2 编译项目

# 编译整个解决方案
dotnet build

成功编译后,您将看到类似以下输出:

Microsoft (R) Build Engine version 17.x.x
...
Build succeeded.
    0 Warning(s)
    0 Error(s)

2.2.3 运行测试

# 运行所有测试
dotnet test

# 运行测试并显示详细输出
dotnet test --logger "console;verbosity=detailed"

2.2.4 运行示例程序

# 进入示例项目目录
cd samples/Esri.Geometry.Samples

# 运行示例
dotnet run

2.3 创建第一个项目

2.3.1 创建控制台应用程序

# 创建新的控制台项目
dotnet new console -n GeometryDemo

# 进入项目目录
cd GeometryDemo

2.3.2 添加项目引用

如果 geometry-api-net 已发布为 NuGet 包,可以直接添加包引用:

dotnet add package Esri.Geometry.Core

或者,添加本地项目引用:

<!-- 编辑 GeometryDemo.csproj -->
<ItemGroup>
    <ProjectReference Include="../path/to/Esri.Geometry.Core/Esri.Geometry.Core.csproj" />
</ItemGroup>

2.3.3 编写第一个程序

编辑 Program.cs 文件:

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;
using Esri.Geometry.Core.IO;

Console.WriteLine("=== geometry-api-net 快速开始 ===\n");

// 1. 创建点
var point = new Point(116.4074, 39.9042);
Console.WriteLine($"创建了一个点:({point.X}, {point.Y})");
Console.WriteLine($"这是北京市中心的经纬度坐标\n");

// 2. 创建包络矩形
var envelope = new Envelope(116.2, 39.7, 116.6, 40.1);
Console.WriteLine($"创建了一个包络矩形:");
Console.WriteLine($"  左下角:({envelope.XMin}, {envelope.YMin})");
Console.WriteLine($"  右上角:({envelope.XMax}, {envelope.YMax})");
Console.WriteLine($"  宽度:{envelope.Width}");
Console.WriteLine($"  高度:{envelope.Height}\n");

// 3. 测试空间关系
bool contains = envelope.Contains(point);
Console.WriteLine($"包络矩形是否包含该点?{(contains ? "是" : "否")}\n");

// 4. 创建多边形
var polygon = new Polygon();
polygon.AddRing(new List<Point>
{
    new Point(116.3, 39.8),
    new Point(116.5, 39.8),
    new Point(116.5, 40.0),
    new Point(116.3, 40.0),
    new Point(116.3, 39.8)  // 闭合环
});
Console.WriteLine($"创建了一个矩形多边形");
Console.WriteLine($"  面积:{polygon.Area:F6} 平方度\n");

// 5. 使用操作符测试包含关系
var containsOp = ContainsOperator.Instance;
bool pointInPolygon = containsOp.Execute(polygon, point);
Console.WriteLine($"多边形是否包含该点?{(pointInPolygon ? "是" : "否")}\n");

// 6. 导出为 WKT
string wkt = WktExportOperator.ExportToWkt(polygon);
Console.WriteLine($"多边形的 WKT 表示:\n{wkt}\n");

// 7. 导出为 GeoJSON
string geoJson = GeoJsonExportOperator.ExportToGeoJson(point);
Console.WriteLine($"点的 GeoJSON 表示:\n{geoJson}\n");

// 8. 使用 GeometryEngine(简化 API)
var point2 = new Point(116.3976, 39.9095);
double distance = GeometryEngine.Distance(point, point2);
Console.WriteLine($"两点之间的距离:{distance:F6} 度");

// 计算大地测量距离
double geodesicDistance = GeometryEngine.GeodesicDistance(point, point2);
Console.WriteLine($"两点之间的大地测量距离:{geodesicDistance:F2} 米\n");

Console.WriteLine("=== 演示完成 ===");

2.3.4 运行程序

dotnet run

预期输出:

=== geometry-api-net 快速开始 ===

创建了一个点:(116.4074, 39.9042)
这是北京市中心的经纬度坐标

创建了一个包络矩形:
  左下角:(116.2, 39.7)
  右上角:(116.6, 40.1)
  宽度:0.4
  高度:0.4

包络矩形是否包含该点?是

创建了一个矩形多边形
  面积:0.040000 平方度

多边形是否包含该点?是

多边形的 WKT 表示:
POLYGON ((116.3 39.8, 116.5 39.8, 116.5 40, 116.3 40, 116.3 39.8))

点的 GeoJSON 表示:
{"type":"Point","coordinates":[116.4074,39.9042]}

两点之间的距离:0.013096 度
两点之间的大地测量距离:1232.45 米

=== 演示完成 ===

2.4 核心 API 快速预览

2.4.1 几何对象创建

// 点
var point = new Point(x, y);
var point3D = new Point(x, y, z);

// 多点
var multiPoint = new MultiPoint();
multiPoint.Add(new Point(x1, y1));
multiPoint.Add(new Point(x2, y2));

// 折线
var polyline = new Polyline();
polyline.AddPath(new List<Point> { p1, p2, p3 });

// 多边形
var polygon = new Polygon();
polygon.AddRing(new List<Point> { p1, p2, p3, p4, p1 });  // 必须闭合

// 包络矩形
var envelope = new Envelope(xMin, yMin, xMax, yMax);

2.4.2 空间关系测试

// 使用 GeometryEngine(推荐)
bool contains = GeometryEngine.Contains(polygon, point);
bool intersects = GeometryEngine.Intersects(g1, g2);
double distance = GeometryEngine.Distance(g1, g2);
bool equals = GeometryEngine.Equals(g1, g2);
bool disjoint = GeometryEngine.Disjoint(g1, g2);
bool within = GeometryEngine.Within(g1, g2);
bool crosses = GeometryEngine.Crosses(g1, g2);
bool touches = GeometryEngine.Touches(g1, g2);
bool overlaps = GeometryEngine.Overlaps(g1, g2);

// 使用操作符(高级用法)
var op = ContainsOperator.Instance;
bool result = op.Execute(geometry1, geometry2);

2.4.3 几何运算

// 缓冲区
var buffer = GeometryEngine.Buffer(point, distance);

// 凸包
var hull = GeometryEngine.ConvexHull(multiPoint);

// 质心
var centroid = GeometryEngine.Centroid(polygon);

// 面积和长度
double area = GeometryEngine.Area(polygon);
double length = GeometryEngine.Length(polyline);

// 简化
var simplified = GeometryEngine.Simplify(polyline, tolerance);

// 概化
var generalized = GeometryEngine.Generalize(polyline, maxDeviation);

// 密化
var densified = GeometryEngine.Densify(polyline, maxSegmentLength);

2.4.4 集合运算

// 并集
var union = GeometryEngine.Union(g1, g2);

// 交集
var intersection = GeometryEngine.Intersection(g1, g2);

// 差集
var difference = GeometryEngine.Difference(g1, g2);

// 对称差
var symDiff = GeometryEngine.SymmetricDifference(g1, g2);

2.4.5 数据格式转换

// WKT
string wkt = GeometryEngine.GeometryToWkt(geometry);
var geom = GeometryEngine.GeometryFromWkt(wkt);

// WKB
byte[] wkb = GeometryEngine.GeometryToWkb(geometry);
var geom2 = GeometryEngine.GeometryFromWkb(wkb);

// GeoJSON
string json = GeometryEngine.GeometryToGeoJson(geometry);
var geom3 = GeometryEngine.GeometryFromGeoJson(json);

// Esri JSON
string esriJson = GeometryEngine.GeometryToEsriJson(geometry);
var geom4 = GeometryEngine.GeometryFromEsriJson(esriJson);

2.5 常见使用场景

2.5.1 场景一:判断点是否在区域内

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;

// 定义服务区域(北京五环内)
var serviceArea = new Polygon();
serviceArea.AddRing(new List<Point>
{
    new Point(116.1, 39.7),
    new Point(116.7, 39.7),
    new Point(116.7, 40.1),
    new Point(116.1, 40.1),
    new Point(116.1, 39.7)
});

// 用户位置
var userLocation = new Point(116.4074, 39.9042);

// 判断用户是否在服务区域内
bool inServiceArea = GeometryEngine.Contains(serviceArea, userLocation);

if (inServiceArea)
{
    Console.WriteLine("您在服务区域内,可以正常使用服务");
}
else
{
    Console.WriteLine("抱歉,您不在服务区域内");
}

2.5.2 场景二:计算两个城市之间的距离

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;

// 城市坐标(经度, 纬度)
var beijing = new Point(116.4074, 39.9042);   // 北京
var shanghai = new Point(121.4737, 31.2304);  // 上海

// 计算大地测量距离
double distanceMeters = GeometryEngine.GeodesicDistance(beijing, shanghai);
double distanceKm = distanceMeters / 1000;

Console.WriteLine($"北京到上海的直线距离:{distanceKm:F2} 公里");
// 输出:北京到上海的直线距离:1067.89 公里

2.5.3 场景三:创建地理围栏缓冲区

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;

// 商店位置
var storeLocation = new Point(116.4074, 39.9042);

// 创建 1 公里(约 0.01 度)的配送范围
var deliveryZone = GeometryEngine.Buffer(storeLocation, 0.01);

// 顾客位置
var customerLocation = new Point(116.41, 39.905);

// 判断是否可配送
bool canDeliver = GeometryEngine.Contains(deliveryZone, customerLocation);
Console.WriteLine($"是否可配送:{(canDeliver ? "是" : "否")}");

2.5.4 场景四:轨迹数据简化

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;

// 原始 GPS 轨迹(包含大量点)
var track = new Polyline();
track.AddPath(new List<Point>
{
    new Point(116.400, 39.900),
    new Point(116.401, 39.901),
    new Point(116.402, 39.902),
    new Point(116.403, 39.903),
    new Point(116.404, 39.904),
    // ... 更多点
});

Console.WriteLine($"原始轨迹点数:{track.GetPath(0).Count}");

// 使用 Douglas-Peucker 算法简化
var simplifiedTrack = GeometryEngine.Simplify(track, tolerance: 0.001);

if (simplifiedTrack is Polyline simplified)
{
    Console.WriteLine($"简化后点数:{simplified.GetPath(0).Count}");
}

2.5.5 场景五:从 WKT 加载地理数据

using Esri.Geometry.Core;
using Esri.Geometry.Core.IO;

// 从数据库或文件读取的 WKT 字符串
string wkt = "POLYGON ((116.3 39.8, 116.5 39.8, 116.5 40.0, 116.3 40.0, 116.3 39.8))";

// 解析 WKT
var geometry = WktImportOperator.ImportFromWkt(wkt);

if (geometry is Polygon polygon)
{
    Console.WriteLine($"加载了一个多边形");
    Console.WriteLine($"环数:{polygon.RingCount}");
    Console.WriteLine($"面积:{polygon.Area}");
    
    // 导出为 GeoJSON 供前端使用
    string geoJson = GeoJsonExportOperator.ExportToGeoJson(polygon);
    Console.WriteLine($"GeoJSON:{geoJson}");
}

2.6 API 使用建议

2.6.1 GeometryEngine vs 操作符

场景 推荐方式 原因
日常开发 GeometryEngine 代码简洁,易于理解
批量处理 操作符 避免方法调用开销
需要传递空间参考 操作符 GeometryEngine 不支持
单元测试 操作符 更容易模拟和测试

2.6.2 性能建议

  1. 复用操作符实例:操作符已是单例,直接使用 Instance 属性
  2. 避免频繁创建几何对象:尽量复用几何对象
  3. 使用简单几何类型:Point 比 MultiPoint 更高效
  4. 合理使用简化:大数据量时先简化再处理

2.6.3 常见错误

// ❌ 错误:多边形环未闭合
var polygon = new Polygon();
polygon.AddRing(new List<Point>
{
    new Point(0, 0),
    new Point(10, 0),
    new Point(10, 10),
    new Point(0, 10)  // 缺少闭合点
});

// ✅ 正确:确保环闭合
polygon.AddRing(new List<Point>
{
    new Point(0, 0),
    new Point(10, 0),
    new Point(10, 10),
    new Point(0, 10),
    new Point(0, 0)  // 闭合
});

// ❌ 错误:直接比较几何对象
if (point1 == point2) { }  // 可能不如预期

// ✅ 正确:使用操作符比较
if (GeometryEngine.Equals(point1, point2)) { }

2.7 下一步

恭喜您完成了快速开始指南!接下来,您可以:

  1. 阅读 第三章:核心几何类型详解,深入了解各种几何类型
  2. 阅读 第四章:空间关系操作符,掌握空间关系测试
  3. 查看 samples/Esri.Geometry.Samples 目录中的更多示例
  4. 运行测试用例,了解各功能的预期行为

2.8 小结

本章我们学习了:

  1. 如何搭建开发环境和构建项目
  2. 如何创建第一个使用 geometry-api-net 的程序
  3. 核心 API 的快速预览
  4. 五个常见使用场景的代码示例
  5. API 使用建议和常见错误

geometry-api-net 的 API 设计简洁直观,通过 GeometryEngine 可以快速上手大多数几何计算任务。在后续章节中,我们将深入探讨每个功能模块的详细用法和实现原理。