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

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
V2EX
大猫的无限游戏
大猫的无限游戏
腾讯CDC
博客园 - Franky
WordPress大学
WordPress大学
Jina AI
Jina AI
GbyAI
GbyAI
云风的 BLOG
云风的 BLOG
B
Blog RSS Feed
Last Week in AI
Last Week in AI
The Cloudflare Blog
V
Visual Studio Blog
P
Proofpoint News Feed
博客园 - 叶小钗
L
LangChain Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Recorded Future
Recorded Future
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
罗磊的独立博客
雷峰网
雷峰网
博客园 - 【当耐特】
Microsoft Security Blog
Microsoft Security Blog
L
LINUX DO - 热门话题
Cisco Talos Blog
Cisco Talos Blog
L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
Spread Privacy
Spread Privacy
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
小众软件
小众软件
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Recent Announcements
Recent Announcements
T
Threat Research - Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
宝玉的分享
宝玉的分享
D
DataBreaches.Net
T
The Exploit Database - CXSecurity.com
Vercel News
Vercel News
IT之家
IT之家
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Troy Hunt's Blog
aimingoo的专栏
aimingoo的专栏

博客园 - 我才是银古

第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 博客园 - 我才是银古

第十章:高级应用与性能优化

10.1 概述

在实际项目中,除了正确使用 geometry-api-net 的 API,还需要考虑性能、可维护性和扩展性。本章将介绍高级使用技巧和性能优化方法。

10.2 架构最佳实践

10.2.1 服务层封装

将几何操作封装为服务,提高代码复用性和可测试性:

public interface IGeometryService
{
    bool IsPointInRegion(Point point, Polygon region);
    double CalculateDistanceMeters(Point p1, Point p2);
    Polygon CreateBuffer(Geometry geometry, double distanceMeters);
    Geometry Simplify(Geometry geometry, double tolerance);
}

public class GeometryService : IGeometryService
{
    private readonly SpatialReference _defaultSR = SpatialReference.Wgs84();
    
    public bool IsPointInRegion(Point point, Polygon region)
    {
        if (point == null || region == null)
            throw new ArgumentNullException();
        
        return GeometryEngine.Contains(region, point);
    }
    
    public double CalculateDistanceMeters(Point p1, Point p2)
    {
        if (p1 == null || p2 == null)
            throw new ArgumentNullException();
        
        return GeometryEngine.GeodesicDistance(p1, p2);
    }
    
    public Polygon CreateBuffer(Geometry geometry, double distanceMeters)
    {
        // 将米转换为度(近似值)
        double distanceDegrees = distanceMeters / 111000.0;
        return GeometryEngine.Buffer(geometry, distanceDegrees);
    }
    
    public Geometry Simplify(Geometry geometry, double tolerance)
    {
        return GeometryEngine.Simplify(geometry, tolerance);
    }
}

// 依赖注入配置
services.AddSingleton<IGeometryService, GeometryService>();

10.2.2 仓储模式

public interface ISpatialRepository<T>
{
    IEnumerable<T> FindInRegion(Polygon region);
    IEnumerable<T> FindNearby(Point location, double radiusMeters);
    T FindNearest(Point location);
}

public class SpatialRepository<T> : ISpatialRepository<T> 
    where T : ISpatialEntity
{
    private readonly List<T> _entities;
    
    public IEnumerable<T> FindInRegion(Polygon region)
    {
        return _entities.Where(e => 
            GeometryEngine.Contains(region, e.Location));
    }
    
    public IEnumerable<T> FindNearby(Point location, double radiusMeters)
    {
        return _entities.Where(e => 
            GeometryEngine.GeodesicDistance(location, e.Location) <= radiusMeters);
    }
    
    public T FindNearest(Point location)
    {
        return _entities
            .OrderBy(e => GeometryEngine.GeodesicDistance(location, e.Location))
            .FirstOrDefault();
    }
}

public interface ISpatialEntity
{
    Point Location { get; }
}

10.2.3 扩展方法

public static class GeometryExtensions
{
    // 链式 API
    public static Geometry Buffer(this Geometry geometry, double distance)
    {
        return GeometryEngine.Buffer(geometry, distance);
    }
    
    public static Geometry Simplify(this Geometry geometry, double tolerance)
    {
        return GeometryEngine.Simplify(geometry, tolerance);
    }
    
    public static string ToWkt(this Geometry geometry)
    {
        return GeometryEngine.GeometryToWkt(geometry);
    }
    
    public static string ToGeoJson(this Geometry geometry)
    {
        return GeometryEngine.GeometryToGeoJson(geometry);
    }
    
    // 便捷方法
    public static bool IsWithin(this Point point, Polygon polygon)
    {
        return GeometryEngine.Contains(polygon, point);
    }
    
    public static double DistanceToMeters(this Point p1, Point p2)
    {
        return GeometryEngine.GeodesicDistance(p1, p2);
    }
    
    // 验证方法
    public static bool IsValidPolygon(this Polygon polygon)
    {
        if (polygon.IsEmpty || polygon.RingCount == 0)
            return false;
        
        var ring = polygon.GetRing(0);
        if (ring.Count < 4)  // 至少 3 个点 + 闭合点
            return false;
        
        // 检查闭合
        var first = ring[0];
        var last = ring[ring.Count - 1];
        return first.Equals(last, 0.0001);
    }
}

// 使用
var simplified = polygon
    .Simplify(0.001)
    .Buffer(0.01);

string wkt = simplified.ToWkt();

10.3 性能优化技巧

10.3.1 包络矩形预过滤

在进行复杂空间操作前,先使用包络矩形进行快速过滤:

public class OptimizedSpatialQuery
{
    private List<Polygon> _regions;
    private Dictionary<Polygon, Envelope> _envelopeCache;
    
    public OptimizedSpatialQuery(List<Polygon> regions)
    {
        _regions = regions;
        // 预计算所有包络矩形
        _envelopeCache = regions.ToDictionary(
            r => r, 
            r => r.GetEnvelope());
    }
    
    public List<Polygon> FindContaining(Point point)
    {
        var results = new List<Polygon>();
        
        foreach (var region in _regions)
        {
            // 快速过滤:检查点是否在包络内
            if (!_envelopeCache[region].Contains(point))
                continue;
            
            // 精确检查
            if (GeometryEngine.Contains(region, point))
            {
                results.Add(region);
            }
        }
        
        return results;
    }
    
    public List<Polygon> FindIntersecting(Polygon query)
    {
        var queryEnvelope = query.GetEnvelope();
        
        return _regions
            .Where(r => _envelopeCache[r].Intersects(queryEnvelope))  // 快速过滤
            .Where(r => GeometryEngine.Intersects(r, query))          // 精确检查
            .ToList();
    }
}

10.3.2 对象复用

避免频繁创建几何对象:

public class GeometryPool
{
    private readonly Stack<Point> _pointPool = new();
    private readonly Stack<Envelope> _envelopePool = new();
    
    public Point RentPoint(double x, double y)
    {
        if (_pointPool.TryPop(out var point))
        {
            point.X = x;
            point.Y = y;
            point.Z = null;
            point.M = null;
            return point;
        }
        return new Point(x, y);
    }
    
    public void ReturnPoint(Point point)
    {
        _pointPool.Push(point);
    }
    
    public Envelope RentEnvelope(double xMin, double yMin, double xMax, double yMax)
    {
        if (_envelopePool.TryPop(out var envelope))
        {
            envelope.XMin = xMin;
            envelope.YMin = yMin;
            envelope.XMax = xMax;
            envelope.YMax = yMax;
            return envelope;
        }
        return new Envelope(xMin, yMin, xMax, yMax);
    }
    
    public void ReturnEnvelope(Envelope envelope)
    {
        _envelopePool.Push(envelope);
    }
}

// 使用
var pool = new GeometryPool();
var point = pool.RentPoint(10, 20);
// 使用 point...
pool.ReturnPoint(point);

10.3.3 批量操作

public class BatchProcessor
{
    public List<bool> BatchContainsTest(Polygon region, List<Point> points)
    {
        var envelope = region.GetEnvelope();
        var results = new List<bool>(points.Count);
        
        foreach (var point in points)
        {
            // 快速过滤
            if (!envelope.Contains(point))
            {
                results.Add(false);
                continue;
            }
            
            results.Add(GeometryEngine.Contains(region, point));
        }
        
        return results;
    }
    
    public List<double> BatchDistanceCalculation(Point origin, List<Point> targets)
    {
        // 使用并行处理
        return targets
            .AsParallel()
            .AsOrdered()
            .Select(t => GeometryEngine.GeodesicDistance(origin, t))
            .ToList();
    }
}

10.3.4 缓存策略

public class GeometryCache
{
    private readonly Dictionary<string, Geometry> _wktCache = new();
    private readonly Dictionary<Geometry, string> _reverseCache = new();
    private readonly Dictionary<Geometry, double> _areaCache = new();
    private readonly Dictionary<Geometry, Envelope> _envelopeCache = new();
    
    public Geometry ParseWkt(string wkt)
    {
        if (_wktCache.TryGetValue(wkt, out var cached))
            return cached;
        
        var geometry = GeometryEngine.GeometryFromWkt(wkt);
        _wktCache[wkt] = geometry;
        return geometry;
    }
    
    public double GetArea(Geometry geometry)
    {
        if (_areaCache.TryGetValue(geometry, out var area))
            return area;
        
        area = GeometryEngine.Area(geometry);
        _areaCache[geometry] = area;
        return area;
    }
    
    public Envelope GetEnvelope(Geometry geometry)
    {
        if (_envelopeCache.TryGetValue(geometry, out var envelope))
            return envelope;
        
        envelope = geometry.GetEnvelope();
        _envelopeCache[geometry] = envelope;
        return envelope;
    }
    
    public void Clear()
    {
        _wktCache.Clear();
        _reverseCache.Clear();
        _areaCache.Clear();
        _envelopeCache.Clear();
    }
}

10.4 错误处理

10.4.1 验证输入

public static class GeometryValidator
{
    public static ValidationResult Validate(Geometry geometry)
    {
        if (geometry == null)
            return ValidationResult.Error("几何对象为空");
        
        if (geometry.IsEmpty)
            return ValidationResult.Warning("几何对象为空几何");
        
        if (geometry is Polygon polygon)
        {
            return ValidatePolygon(polygon);
        }
        
        if (geometry is Polyline polyline)
        {
            return ValidatePolyline(polyline);
        }
        
        return ValidationResult.Success();
    }
    
    private static ValidationResult ValidatePolygon(Polygon polygon)
    {
        if (polygon.RingCount == 0)
            return ValidationResult.Error("多边形没有环");
        
        var ring = polygon.GetRing(0);
        if (ring.Count < 4)
            return ValidationResult.Error("多边形环至少需要 4 个点(含闭合点)");
        
        // 检查闭合
        var first = ring[0];
        var last = ring[ring.Count - 1];
        if (!first.Equals(last, 0.0001))
            return ValidationResult.Warning("多边形环未闭合");
        
        // 检查面积
        if (polygon.Area < 0.00000001)
            return ValidationResult.Warning("多边形面积过小");
        
        return ValidationResult.Success();
    }
    
    private static ValidationResult ValidatePolyline(Polyline polyline)
    {
        if (polyline.PathCount == 0)
            return ValidationResult.Error("折线没有路径");
        
        var path = polyline.GetPath(0);
        if (path.Count < 2)
            return ValidationResult.Error("折线路径至少需要 2 个点");
        
        if (polyline.Length < 0.00000001)
            return ValidationResult.Warning("折线长度过短");
        
        return ValidationResult.Success();
    }
}

public class ValidationResult
{
    public bool IsValid { get; }
    public string Message { get; }
    public ValidationLevel Level { get; }
    
    public static ValidationResult Success() => new(true, null, ValidationLevel.None);
    public static ValidationResult Warning(string msg) => new(true, msg, ValidationLevel.Warning);
    public static ValidationResult Error(string msg) => new(false, msg, ValidationLevel.Error);
    
    private ValidationResult(bool isValid, string message, ValidationLevel level)
    {
        IsValid = isValid;
        Message = message;
        Level = level;
    }
}

public enum ValidationLevel { None, Warning, Error }

10.4.2 安全包装

public static class SafeGeometryEngine
{
    public static Result<bool> TryContains(Geometry g1, Geometry g2)
    {
        try
        {
            if (g1 == null || g2 == null)
                return Result<bool>.Failure("输入几何对象为空");
            
            return Result<bool>.Ok(GeometryEngine.Contains(g1, g2));
        }
        catch (Exception ex)
        {
            return Result<bool>.Failure($"Contains 操作失败: {ex.Message}");
        }
    }
    
    public static Result<Geometry> TryParseWkt(string wkt)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(wkt))
                return Result<Geometry>.Failure("WKT 字符串为空");
            
            var geometry = GeometryEngine.GeometryFromWkt(wkt);
            return Result<Geometry>.Ok(geometry);
        }
        catch (FormatException ex)
        {
            return Result<Geometry>.Failure($"WKT 格式错误: {ex.Message}");
        }
        catch (Exception ex)
        {
            return Result<Geometry>.Failure($"解析失败: {ex.Message}");
        }
    }
}

public class Result<T>
{
    public bool IsSuccess { get; }
    public T Value { get; }
    public string Error { get; }
    
    public static Result<T> Ok(T value) => new(true, value, null);
    public static Result<T> Failure(string error) => new(false, default, error);
    
    private Result(bool success, T value, string error)
    {
        IsSuccess = success;
        Value = value;
        Error = error;
    }
}

10.5 测试策略

10.5.1 单元测试

using Xunit;

public class GeometryServiceTests
{
    private readonly IGeometryService _service;
    
    public GeometryServiceTests()
    {
        _service = new GeometryService();
    }
    
    [Fact]
    public void IsPointInRegion_PointInside_ReturnsTrue()
    {
        // Arrange
        var polygon = CreateSquarePolygon(0, 0, 100, 100);
        var point = new Point(50, 50);
        
        // Act
        bool result = _service.IsPointInRegion(point, polygon);
        
        // Assert
        Assert.True(result);
    }
    
    [Fact]
    public void IsPointInRegion_PointOutside_ReturnsFalse()
    {
        var polygon = CreateSquarePolygon(0, 0, 100, 100);
        var point = new Point(150, 150);
        
        bool result = _service.IsPointInRegion(point, polygon);
        
        Assert.False(result);
    }
    
    [Theory]
    [InlineData(0, 0, 3, 4, 5)]        // 3-4-5 三角形
    [InlineData(0, 0, 0, 10, 10)]      // 垂直线
    [InlineData(0, 0, 10, 0, 10)]      // 水平线
    public void Distance_KnownValues_ReturnsExpected(
        double x1, double y1, double x2, double y2, double expected)
    {
        var p1 = new Point(x1, y1);
        var p2 = new Point(x2, y2);
        
        double distance = GeometryEngine.Distance(p1, p2);
        
        Assert.Equal(expected, distance, precision: 6);
    }
    
    [Fact]
    public void WktRoundTrip_PreservesGeometry()
    {
        var original = CreateSquarePolygon(0, 0, 100, 100);
        
        string wkt = GeometryEngine.GeometryToWkt(original);
        var parsed = GeometryEngine.GeometryFromWkt(wkt);
        
        Assert.True(GeometryEngine.Equals(original, parsed));
    }
    
    private Polygon CreateSquarePolygon(double x1, double y1, double x2, double y2)
    {
        var polygon = new Polygon();
        polygon.AddRing(new List<Point>
        {
            new Point(x1, y1),
            new Point(x2, y1),
            new Point(x2, y2),
            new Point(x1, y2),
            new Point(x1, y1)
        });
        return polygon;
    }
}

10.5.2 性能测试

using BenchmarkDotNet.Attributes;

[MemoryDiagnoser]
public class GeometryBenchmarks
{
    private Polygon _polygon;
    private List<Point> _testPoints;
    
    [GlobalSetup]
    public void Setup()
    {
        _polygon = CreateComplexPolygon(1000);  // 1000 个顶点
        _testPoints = GenerateRandomPoints(10000);
    }
    
    [Benchmark]
    public int ContainsTest_WithPrefilter()
    {
        var envelope = _polygon.GetEnvelope();
        int count = 0;
        
        foreach (var point in _testPoints)
        {
            if (envelope.Contains(point) && 
                GeometryEngine.Contains(_polygon, point))
            {
                count++;
            }
        }
        
        return count;
    }
    
    [Benchmark]
    public int ContainsTest_WithoutPrefilter()
    {
        int count = 0;
        
        foreach (var point in _testPoints)
        {
            if (GeometryEngine.Contains(_polygon, point))
            {
                count++;
            }
        }
        
        return count;
    }
}

10.6 调试技巧

10.6.1 几何可视化

public static class GeometryDebugger
{
    public static void PrintGeometry(Geometry geometry, string name = "Geometry")
    {
        Console.WriteLine($"=== {name} ===");
        Console.WriteLine($"Type: {geometry.Type}");
        Console.WriteLine($"IsEmpty: {geometry.IsEmpty}");
        Console.WriteLine($"Dimension: {geometry.Dimension}");
        
        var envelope = geometry.GetEnvelope();
        Console.WriteLine($"Envelope: ({envelope.XMin:F4}, {envelope.YMin:F4}) - ({envelope.XMax:F4}, {envelope.YMax:F4})");
        Console.WriteLine($"WKT: {GeometryEngine.GeometryToWkt(geometry)}");
        
        if (geometry is Polygon polygon)
        {
            Console.WriteLine($"RingCount: {polygon.RingCount}");
            Console.WriteLine($"Area: {polygon.Area:F4}");
        }
        
        if (geometry is Polyline polyline)
        {
            Console.WriteLine($"PathCount: {polyline.PathCount}");
            Console.WriteLine($"Length: {polyline.Length:F4}");
        }
        
        Console.WriteLine();
    }
    
    public static string ToSvg(Geometry geometry, double width = 200, double height = 200)
    {
        var envelope = geometry.GetEnvelope();
        double scaleX = width / envelope.Width;
        double scaleY = height / envelope.Height;
        double scale = Math.Min(scaleX, scaleY);
        
        var sb = new StringBuilder();
        sb.AppendLine($"<svg width=\"{width}\" height=\"{height}\" xmlns=\"http://www.w3.org/2000/svg\">");
        
        if (geometry is Polygon polygon)
        {
            foreach (var ring in polygon.GetRings())
            {
                var points = string.Join(" ", ring.Select(p => 
                    $"{(p.X - envelope.XMin) * scale:F2},{height - (p.Y - envelope.YMin) * scale:F2}"));
                sb.AppendLine($"  <polygon points=\"{points}\" fill=\"blue\" fill-opacity=\"0.3\" stroke=\"blue\" stroke-width=\"1\"/>");
            }
        }
        
        sb.AppendLine("</svg>");
        return sb.ToString();
    }
}

10.7 小结

本章介绍了 geometry-api-net 的高级应用和性能优化:

架构最佳实践

  • 服务层封装
  • 仓储模式
  • 扩展方法

性能优化

  • 包络矩形预过滤
  • 对象复用
  • 批量操作
  • 缓存策略

错误处理

  • 输入验证
  • 安全包装

测试策略

  • 单元测试
  • 性能测试

在下一章中,我们将通过实战案例,展示如何在实际项目中综合运用这些技术。