第14章-高级功能与性能优化
第14章:高级功能与性能优化
14.1 性能优化概述
在处理大量空间数据时,性能优化至关重要。本章介绍 NetTopologySuite 的高级功能和性能优化技巧。
14.2 PreparedGeometry 优化
14.2.1 基本使用
PreparedGeometry 通过预计算几何的空间索引,大幅提高重复空间关系查询的性能。
using NetTopologySuite.Geometries;
using NetTopologySuite.Geometries.Prepared;
var factory = new GeometryFactory();
// 创建复杂多边形
var polygon = factory.CreatePolygon(new Coordinate[]
{
new Coordinate(0, 0), new Coordinate(100, 0),
new Coordinate(100, 100), new Coordinate(0, 100),
new Coordinate(0, 0)
});
// 创建 PreparedGeometry
var prepared = PreparedGeometryFactory.Prepare(polygon);
// 创建测试点
var points = Enumerable.Range(0, 100000)
.Select(i => factory.CreatePoint(new Coordinate(
Random.Shared.NextDouble() * 150 - 25,
Random.Shared.NextDouble() * 150 - 25)))
.ToList();
// 性能比较
var sw = System.Diagnostics.Stopwatch.StartNew();
// 使用普通几何
var normalCount = points.Count(p => polygon.Contains(p));
var normalTime = sw.ElapsedMilliseconds;
sw.Restart();
// 使用 PreparedGeometry
var preparedCount = points.Count(p => prepared.Contains(p));
var preparedTime = sw.ElapsedMilliseconds;
Console.WriteLine($"普通方法: {normalTime}ms, 结果: {normalCount}");
Console.WriteLine($"Prepared: {preparedTime}ms, 结果: {preparedCount}");
Console.WriteLine($"性能提升: {(double)normalTime / preparedTime:F1}x");
14.2.2 支持的操作
var prepared = PreparedGeometryFactory.Prepare(polygon);
// 支持的空间关系
bool contains = prepared.Contains(point);
bool containsProperly = prepared.ContainsProperly(point);
bool covers = prepared.Covers(point);
bool coveredBy = prepared.CoveredBy(otherPolygon);
bool intersects = prepared.Intersects(point);
bool within = prepared.Within(otherPolygon);
14.3 空间索引
14.3.1 STRtree 索引
using NetTopologySuite.Index.Strtree;
// 创建索引
var tree = new STRtree<Geometry>();
// 批量添加几何
foreach (var geom in geometries)
{
tree.Insert(geom.EnvelopeInternal, geom);
}
// 必须在查询前构建
tree.Build();
// 范围查询
var searchEnvelope = new Envelope(0, 50, 0, 50);
var candidates = tree.Query(searchEnvelope);
// 精确筛选
var matches = candidates
.Where(g => g.Intersects(queryGeometry))
.ToList();
14.3.2 自定义索引项
public class IndexedFeature
{
public int Id { get; set; }
public Geometry Geometry { get; set; }
public Dictionary<string, object> Properties { get; set; }
}
// 创建索引
var featureIndex = new STRtree<IndexedFeature>();
foreach (var feature in features)
{
featureIndex.Insert(feature.Geometry.EnvelopeInternal, feature);
}
featureIndex.Build();
// 查询
var results = featureIndex.Query(searchEnvelope)
.Where(f => f.Geometry.Intersects(queryGeometry))
.ToList();
14.3.3 Quadtree 四叉树
using NetTopologySuite.Index.Quadtree;
var quadtree = new Quadtree<Geometry>();
// 添加几何
foreach (var geom in geometries)
{
quadtree.Insert(geom.EnvelopeInternal, geom);
}
// 查询
var results = quadtree.Query(searchEnvelope);
// 删除
quadtree.Remove(geom.EnvelopeInternal, geom);
14.4 并行处理
14.4.1 并行空间查询
using System.Collections.Concurrent;
public class ParallelSpatialQuery
{
private readonly STRtree<Geometry> _index;
private readonly PreparedGeometry _preparedQuery;
public ParallelSpatialQuery(IEnumerable<Geometry> geometries, Geometry queryGeometry)
{
_index = new STRtree<Geometry>();
foreach (var geom in geometries)
{
_index.Insert(geom.EnvelopeInternal, geom);
}
_index.Build();
_preparedQuery = PreparedGeometryFactory.Prepare(queryGeometry);
}
/// <summary>
/// 并行查询
/// </summary>
public List<Geometry> QueryParallel(Envelope extent)
{
var candidates = _index.Query(extent);
var results = new ConcurrentBag<Geometry>();
Parallel.ForEach(candidates, geom =>
{
if (_preparedQuery.Intersects(geom))
{
results.Add(geom);
}
});
return results.ToList();
}
}
14.4.2 并行几何运算
public class ParallelGeometryOperations
{
/// <summary>
/// 并行缓冲区计算
/// </summary>
public static List<Geometry> ParallelBuffer(
IEnumerable<Geometry> geometries,
double distance)
{
return geometries
.AsParallel()
.Select(g => g.Buffer(distance))
.ToList();
}
/// <summary>
/// 并行简化
/// </summary>
public static List<Geometry> ParallelSimplify(
IEnumerable<Geometry> geometries,
double tolerance)
{
return geometries
.AsParallel()
.Select(g => g.Simplify(tolerance))
.ToList();
}
/// <summary>
/// 并行空间关系判断
/// </summary>
public static List<(int Index, bool Result)> ParallelContains(
Geometry container,
IList<Geometry> geometries)
{
var prepared = PreparedGeometryFactory.Prepare(container);
return geometries
.AsParallel()
.Select((g, i) => (i, prepared.Contains(g)))
.ToList();
}
}
14.5 内存优化
14.5.1 几何池化
public class GeometryPool
{
private readonly ConcurrentDictionary<int, ConcurrentBag<Coordinate[]>> _coordinateArrayPool;
private readonly GeometryFactory _factory;
public GeometryPool(int srid = 4326)
{
_coordinateArrayPool = new ConcurrentDictionary<int, ConcurrentBag<Coordinate[]>>();
_factory = new GeometryFactory(new PrecisionModel(), srid);
}
/// <summary>
/// 获取坐标数组
/// </summary>
public Coordinate[] RentCoordinates(int size)
{
if (_coordinateArrayPool.TryGetValue(size, out var pool) && pool.TryTake(out var array))
{
return array;
}
return new Coordinate[size];
}
/// <summary>
/// 归还坐标数组
/// </summary>
public void ReturnCoordinates(Coordinate[] array)
{
var pool = _coordinateArrayPool.GetOrAdd(array.Length, _ => new ConcurrentBag<Coordinate[]>());
// 清理数组
Array.Clear(array, 0, array.Length);
pool.Add(array);
}
}
14.5.2 流式处理大文件
public class StreamingShapefileProcessor
{
/// <summary>
/// 流式处理 Shapefile(避免一次性加载到内存)
/// </summary>
public IEnumerable<Feature> StreamFeatures(string path)
{
using var reader = Shapefile.OpenRead(path);
while (reader.Read())
{
var geometry = reader.Geometry;
var attributes = new AttributesTable();
for (int i = 0; i < reader.Fields.Count; i++)
{
attributes.Add(reader.Fields[i].Name, reader.GetValue(i));
}
yield return new Feature(geometry, attributes);
}
}
/// <summary>
/// 分批处理
/// </summary>
public void ProcessInBatches(string path, int batchSize, Action<List<Feature>> processor)
{
var batch = new List<Feature>(batchSize);
foreach (var feature in StreamFeatures(path))
{
batch.Add(feature);
if (batch.Count >= batchSize)
{
processor(batch);
batch.Clear();
}
}
if (batch.Count > 0)
{
processor(batch);
}
}
}
14.6 精度控制
14.6.1 精度模型
// 不同精度模型的影响
var floatingPrecision = new PrecisionModel(PrecisionModels.Floating);
var fixedPrecision = new PrecisionModel(1000000); // 6位小数
var factoryFloat = new GeometryFactory(floatingPrecision);
var factoryFixed = new GeometryFactory(fixedPrecision);
// 精度对运算的影响
var coord = new Coordinate(116.40739999999999, 39.90419999999999);
var pointFloat = factoryFloat.CreatePoint(coord);
var pointFixed = factoryFixed.CreatePoint(coord);
Console.WriteLine($"浮点: {pointFloat.AsText()}"); // 完整精度
Console.WriteLine($"固定: {pointFixed.AsText()}"); // 6位小数
14.6.2 几何精度降低
using NetTopologySuite.Precision;
// 降低几何精度
var reducer = new GeometryPrecisionReducer(new PrecisionModel(1000));
var original = factory.CreatePolygon(new Coordinate[]
{
new Coordinate(0.123456789, 0.987654321),
new Coordinate(10.111111111, 0.222222222),
new Coordinate(10.333333333, 10.444444444),
new Coordinate(0.555555555, 10.666666666),
new Coordinate(0.123456789, 0.987654321)
});
var reduced = reducer.Reduce(original);
Console.WriteLine($"原始: {original.AsText()}");
Console.WriteLine($"降低后: {reduced.AsText()}");
14.7 高级几何操作
14.7.1 NG 覆盖引擎
using NetTopologySuite;
using NetTopologySuite.Geometries;
// 使用 NG 覆盖引擎(更稳定、更快)
var services = new NtsGeometryServices(
coordinateSequenceFactory: CoordinateArraySequenceFactory.Instance,
precisionModel: new PrecisionModel(1000000),
srid: 4326,
geometryOverlay: GeometryOverlay.NG, // 使用 NG 引擎
coordinateEqualityComparer: new CoordinateEqualityComparer()
);
var factory = services.CreateGeometryFactory();
// 使用 NG 引擎进行叠加分析
var union = polygon1.Union(polygon2);
var intersection = polygon1.Intersection(polygon2);
14.7.2 健壮的几何运算
using NetTopologySuite.Operation.Overlay.Snap;
// 使用 Snap 进行健壮的叠加运算
var snapTolerance = 0.00001;
var union = SnapIfNeededOverlayOp.Union(polygon1, polygon2, snapTolerance);
var intersection = SnapIfNeededOverlayOp.Intersection(polygon1, polygon2, snapTolerance);
14.8 基准测试
14.8.1 性能测试框架
public class GeometryBenchmark
{
private readonly GeometryFactory _factory;
private readonly List<Geometry> _testGeometries;
private readonly Geometry _queryGeometry;
public GeometryBenchmark(int geometryCount = 10000)
{
_factory = new GeometryFactory(new PrecisionModel(), 4326);
_testGeometries = GenerateRandomPolygons(geometryCount);
_queryGeometry = _factory.CreatePolygon(new Coordinate[]
{
new Coordinate(40, 40), new Coordinate(60, 40),
new Coordinate(60, 60), new Coordinate(40, 60),
new Coordinate(40, 40)
});
}
public void RunBenchmarks()
{
Console.WriteLine("性能基准测试");
Console.WriteLine("=".PadRight(50, '='));
BenchmarkContainsQuery();
BenchmarkPreparedContainsQuery();
BenchmarkIndexedQuery();
BenchmarkBufferOperation();
BenchmarkUnionOperation();
}
private void BenchmarkContainsQuery()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var count = _testGeometries.Count(g => _queryGeometry.Intersects(g));
sw.Stop();
Console.WriteLine($"普通相交查询: {sw.ElapsedMilliseconds}ms, 结果: {count}");
}
private void BenchmarkPreparedContainsQuery()
{
var prepared = PreparedGeometryFactory.Prepare(_queryGeometry);
var sw = System.Diagnostics.Stopwatch.StartNew();
var count = _testGeometries.Count(g => prepared.Intersects(g));
sw.Stop();
Console.WriteLine($"Prepared查询: {sw.ElapsedMilliseconds}ms, 结果: {count}");
}
private void BenchmarkIndexedQuery()
{
var tree = new STRtree<Geometry>();
foreach (var geom in _testGeometries)
{
tree.Insert(geom.EnvelopeInternal, geom);
}
tree.Build();
var prepared = PreparedGeometryFactory.Prepare(_queryGeometry);
var sw = System.Diagnostics.Stopwatch.StartNew();
var candidates = tree.Query(_queryGeometry.EnvelopeInternal);
var count = candidates.Count(g => prepared.Intersects(g));
sw.Stop();
Console.WriteLine($"索引+Prepared: {sw.ElapsedMilliseconds}ms, 结果: {count}");
}
private void BenchmarkBufferOperation()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var buffers = _testGeometries.Take(1000).Select(g => g.Buffer(1)).ToList();
sw.Stop();
Console.WriteLine($"缓冲区运算(1000): {sw.ElapsedMilliseconds}ms");
}
private void BenchmarkUnionOperation()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var union = UnaryUnionOp.Union(_testGeometries.Take(100));
sw.Stop();
Console.WriteLine($"联合运算(100): {sw.ElapsedMilliseconds}ms");
}
private List<Geometry> GenerateRandomPolygons(int count)
{
var polygons = new List<Geometry>(count);
var random = new Random(42);
for (int i = 0; i < count; i++)
{
var x = random.NextDouble() * 100;
var y = random.NextDouble() * 100;
var size = random.NextDouble() * 2 + 0.5;
polygons.Add(_factory.CreatePolygon(new Coordinate[]
{
new Coordinate(x, y),
new Coordinate(x + size, y),
new Coordinate(x + size, y + size),
new Coordinate(x, y + size),
new Coordinate(x, y)
}));
}
return polygons;
}
}
14.9 本章小结
本章介绍了高级功能与性能优化:
- PreparedGeometry:预计算几何索引提升查询性能
- 空间索引:STRtree 和 Quadtree 的使用
- 并行处理:并行空间查询和几何运算
- 内存优化:几何池化和流式处理
- 精度控制:精度模型和精度降低
- 高级几何操作:NG 覆盖引擎和健壮运算
- 基准测试:性能测试框架
14.10 下一步
下一章是实战案例与最佳实践。
相关资源:

浙公网安备 33010602011771号