尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

04-空间关系操作符

04-空间关系操作符
📅 发布时间:2026/6/22 3:42:41

第四章:空间关系操作符

4.1 空间关系概述

空间关系是 GIS 分析的基础,用于描述两个几何对象在空间上的相对位置关系。geometry-api-net 提供了 9 种符合 OGC 标准的空间关系测试操作符。

4.1.1 空间关系类型

关系 操作符 说明
包含 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 部分重叠

4.1.2 操作符设计模式

所有空间关系操作符都实现了 IBinaryGeometryOperator<bool> 接口(除了 DistanceOperator 返回 double):

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

操作符采用单例模式,通过 Instance 属性获取实例:

// 使用操作符
bool result = ContainsOperator.Instance.Execute(geometry1, geometry2);// 或使用 GeometryEngine
bool result = GeometryEngine.Contains(geometry1, geometry2);

4.2 Contains(包含)

4.2.1 定义

如果几何对象 A 包含几何对象 B,意味着 B 的所有点都在 A 的内部或边界上,且 B 的内部与 A 的内部相交。

数学表达:

  • B 在 A 内部:B ⊆ A
  • Contains(A, B) = true 等价于 Within(B, A) = true

4.2.2 API

public class ContainsOperator : IBinaryGeometryOperator<bool>
{public static ContainsOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.2.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;// 包络矩形包含点
var envelope = new Envelope(0, 0, 100, 100);
var pointInside = new Point(50, 50);
var pointOutside = new Point(150, 50);bool contains1 = ContainsOperator.Instance.Execute(envelope, pointInside);  // true
bool contains2 = ContainsOperator.Instance.Execute(envelope, pointOutside); // false// 使用 GeometryEngine
bool contains3 = GeometryEngine.Contains(envelope, pointInside);  // true// 多边形包含点(使用光线投射算法)
var polygon = new Polygon();
polygon.AddRing(new List<Point>
{new Point(0, 0),new Point(100, 0),new Point(100, 100),new Point(0, 100),new Point(0, 0)
});bool inPolygon = GeometryEngine.Contains(polygon, new Point(50, 50));  // true
bool inPolygon2 = GeometryEngine.Contains(polygon, new Point(150, 50)); // false

4.2.4 实现原理:光线投射算法

对于点在多边形内的测试,ContainsOperator 使用光线投射算法(Ray Casting Algorithm):

private static bool IsPointInPolygon(Polygon polygon, Point point)
{if (polygon.IsEmpty || polygon.RingCount == 0)return false;var inside = false;var x = point.X;var y = point.Y;// 测试外环var ring = polygon.GetRing(0);if (ring.Count < 3) return false;// 光线投射:从点向右发射一条射线,计算与多边形边界的交点数// 奇数次交点 = 在内部,偶数次交点 = 在外部for (int i = 0, j = ring.Count - 1; i < ring.Count; j = i++){double xi = ring[i].X, yi = ring[i].Y;double xj = ring[j].X, yj = ring[j].Y;if (((yi > y) != (yj > y)) &&(x < (xj - xi) * (y - yi) / (yj - yi) + xi)){inside = !inside;}}// 检查孔洞for (var ringIndex = 1; ringIndex < polygon.RingCount; ringIndex++){var holeRing = polygon.GetRing(ringIndex);// ... 类似的光线投射检测// 如果点在孔洞内,则不在多边形内}return inside;
}

算法复杂度:O(n),其中 n 是多边形顶点数。

4.2.5 应用场景

// 场景:判断用户是否在服务区域内
var serviceArea = new Polygon();
serviceArea.AddRing(new List<Point>
{new Point(116.2, 39.7),new Point(116.6, 39.7),new Point(116.6, 40.1),new Point(116.2, 40.1),new Point(116.2, 39.7)
});var userLocation = new Point(116.4, 39.9);if (GeometryEngine.Contains(serviceArea, userLocation))
{Console.WriteLine("用户在服务区域内");
}
else
{Console.WriteLine("用户不在服务区域内");
}

4.3 Intersects(相交)

4.3.1 定义

如果两个几何对象有任何共同的点,则它们相交。这是最常用的空间关系测试。

数学表达:A ∩ B ≠ ∅

4.3.2 API

public class IntersectsOperator : IBinaryGeometryOperator<bool>
{public static IntersectsOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.3.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 两个重叠的包络矩形
var env1 = new Envelope(0, 0, 100, 100);
var env2 = new Envelope(50, 50, 150, 150);
var env3 = new Envelope(200, 200, 300, 300);bool intersects1 = GeometryEngine.Intersects(env1, env2);  // true
bool intersects2 = GeometryEngine.Intersects(env1, env3);  // false// 点与包络矩形
var point = new Point(50, 50);
bool intersects3 = GeometryEngine.Intersects(env1, point);  // true// 多边形相交
var poly1 = new Polygon();
poly1.AddRing(new List<Point>
{new Point(0, 0),new Point(50, 0),new Point(50, 50),new Point(0, 50),new Point(0, 0)
});var poly2 = new Polygon();
poly2.AddRing(new List<Point>
{new Point(25, 25),new Point(75, 25),new Point(75, 75),new Point(25, 75),new Point(25, 25)
});bool polyIntersects = GeometryEngine.Intersects(poly1, poly2);  // true

4.3.4 实现原理

IntersectsOperator 根据不同的几何类型组合采用不同的算法:

public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null)
{// 空几何不相交if (geometry1.IsEmpty || geometry2.IsEmpty)return false;// 包络矩形相交测试(快速过滤)if (geometry1 is Envelope env1 && geometry2 is Envelope env2)return env1.Intersects(env2);// 点与包络矩形if (geometry1 is Envelope env && geometry2 is Point pt)return env.Contains(pt);// 点与多边形if (geometry1 is Polygon poly && geometry2 is Point p)return ContainsOperator.Instance.Execute(poly, p);// 默认使用包络矩形相交测试var envelope1 = geometry1.GetEnvelope();var envelope2 = geometry2.GetEnvelope();return envelope1.Intersects(envelope2);
}

4.3.5 应用场景

// 场景:查找与查询范围相交的所有对象
var queryExtent = new Envelope(116.3, 39.8, 116.5, 40.0);
var buildings = new List<Polygon> { /* 建筑物多边形列表 */ };var intersectingBuildings = buildings.Where(b => GeometryEngine.Intersects(queryExtent, b)).ToList();Console.WriteLine($"找到 {intersectingBuildings.Count} 个相交的建筑物");

4.4 Distance(距离)

4.4.1 定义

计算两个几何对象之间的最短欧几里得距离。如果两个几何对象相交,距离为 0。

4.4.2 API

public class DistanceOperator : IBinaryGeometryOperator<double>
{public static DistanceOperator Instance { get; }public double Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.4.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 两点之间的距离
var point1 = new Point(0, 0);
var point2 = new Point(3, 4);double distance = GeometryEngine.Distance(point1, point2);
Console.WriteLine($"距离:{distance}");  // 5(勾股定理:3² + 4² = 5²)// 点到包络矩形的距离
var envelope = new Envelope(10, 10, 20, 20);
var testPoint = new Point(0, 0);double distToEnv = GeometryEngine.Distance(testPoint, envelope);
Console.WriteLine($"点到矩形的距离:{distToEnv:F4}");  // ~14.14// 点在矩形内部,距离为 0
var pointInside = new Point(15, 15);
double distInside = GeometryEngine.Distance(pointInside, envelope);
Console.WriteLine($"内部点距离:{distInside}");  // 0

4.4.4 实现原理

public double Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null)
{// 点与点的距离if (geometry1 is Point p1 && geometry2 is Point p2)return p1.Distance(p2);// 点与包络矩形的距离if (geometry1 is Point point && geometry2 is Envelope envelope){// 如果点在包络内,距离为 0if (envelope.Contains(point))return 0;// 计算点到最近边的距离double dx = Math.Max(0, Math.Max(envelope.XMin - point.X, point.X - envelope.XMax));double dy = Math.Max(0, Math.Max(envelope.YMin - point.Y, point.Y - envelope.YMax));return Math.Sqrt(dx * dx + dy * dy);}// 包络矩形之间的距离if (geometry1 is Envelope env1 && geometry2 is Envelope env2){if (env1.Intersects(env2))return 0;double dx = Math.Max(0, Math.Max(env1.XMin - env2.XMax, env2.XMin - env1.XMax));double dy = Math.Max(0, Math.Max(env1.YMin - env2.YMax, env2.YMin - env1.YMax));return Math.Sqrt(dx * dx + dy * dy);}// 对于其他几何类型,使用包络近似return Execute(geometry1.GetEnvelope(), geometry2.GetEnvelope());
}

4.4.5 应用场景

// 场景:查找最近的商店
var userLocation = new Point(116.4, 39.9);
var stores = new List<(string name, Point location)>
{("商店A", new Point(116.41, 39.91)),("商店B", new Point(116.38, 39.88)),("商店C", new Point(116.45, 39.95))
};var nearestStore = stores.OrderBy(s => GeometryEngine.Distance(userLocation, s.location)).First();double nearestDistance = GeometryEngine.Distance(userLocation, nearestStore.location);
Console.WriteLine($"最近的商店:{nearestStore.name},距离:{nearestDistance:F4} 度");

4.5 Equals(相等)

4.5.1 定义

判断两个几何对象在空间上是否完全相同(考虑容差)。

4.5.2 API

public class EqualsOperator : IBinaryGeometryOperator<bool>
{public static EqualsOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.5.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 相同坐标的点
var point1 = new Point(10.0, 20.0);
var point2 = new Point(10.0, 20.0);bool equals1 = GeometryEngine.Equals(point1, point2);  // true// 容差范围内的点
var point3 = new Point(10.0000001, 20.0000001);
bool equals2 = GeometryEngine.Equals(point1, point3);  // true(在默认容差内)// 不同的点
var point4 = new Point(11.0, 21.0);
bool equals3 = GeometryEngine.Equals(point1, point4);  // false// 相同的包络矩形
var env1 = new Envelope(0, 0, 100, 100);
var env2 = new Envelope(0, 0, 100, 100);
bool equals4 = GeometryEngine.Equals(env1, env2);  // true

4.5.4 实现原理

public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null)
{if (geometry1 == null || geometry2 == null)return false;if (geometry1.Type != geometry2.Type)return false;if (geometry1.IsEmpty && geometry2.IsEmpty)return true;if (geometry1.IsEmpty != geometry2.IsEmpty)return false;// 点的相等性if (geometry1 is Point p1 && geometry2 is Point p2)return p1.Equals(p2, GeometryConstants.DefaultTolerance);// 包络矩形的相等性if (geometry1 is Envelope env1 && geometry2 is Envelope env2){return Math.Abs(env1.XMin - env2.XMin) <= GeometryConstants.DefaultTolerance &&Math.Abs(env1.YMin - env2.YMin) <= GeometryConstants.DefaultTolerance &&Math.Abs(env1.XMax - env2.XMax) <= GeometryConstants.DefaultTolerance &&Math.Abs(env1.YMax - env2.YMax) <= GeometryConstants.DefaultTolerance;}// 其他类型使用包络比较var envelope1 = geometry1.GetEnvelope();var envelope2 = geometry2.GetEnvelope();return Execute(envelope1, envelope2);
}

4.6 Disjoint(分离)

4.6.1 定义

如果两个几何对象没有任何共同的点,则它们分离。这是 Intersects 的逆操作。

数学表达:A ∩ B = ∅

4.6.2 API

public class DisjointOperator : IBinaryGeometryOperator<bool>
{public static DisjointOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.6.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;var env1 = new Envelope(0, 0, 10, 10);
var env2 = new Envelope(20, 20, 30, 30);  // 完全分离
var env3 = new Envelope(5, 5, 15, 15);    // 重叠bool disjoint1 = GeometryEngine.Disjoint(env1, env2);  // true
bool disjoint2 = GeometryEngine.Disjoint(env1, env3);  // false// 等价于 !Intersects
bool notIntersects = !GeometryEngine.Intersects(env1, env2);  // true

4.6.4 实现原理

public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null)
{// Disjoint 是 Intersects 的逆return !IntersectsOperator.Instance.Execute(geometry1, geometry2, spatialRef);
}

4.7 Within(在内部)

4.7.1 定义

如果几何对象 A 完全在几何对象 B 的内部,则 A 在 B 内。这是 Contains 的逆操作。

数学表达:Within(A, B) = Contains(B, A)

4.7.2 API

public class WithinOperator : IBinaryGeometryOperator<bool>
{public static WithinOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.7.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;var smallEnv = new Envelope(20, 20, 30, 30);
var largeEnv = new Envelope(0, 0, 100, 100);bool within1 = GeometryEngine.Within(smallEnv, largeEnv);  // true
bool within2 = GeometryEngine.Within(largeEnv, smallEnv);  // false// 点在多边形内
var point = new Point(50, 50);
var polygon = new Polygon();
polygon.AddRing(new List<Point>
{new Point(0, 0),new Point(100, 0),new Point(100, 100),new Point(0, 100),new Point(0, 0)
});bool pointWithin = GeometryEngine.Within(point, polygon);  // true

4.7.4 实现原理

public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null)
{// Within 是 Contains 的逆:A within B = B contains Areturn ContainsOperator.Instance.Execute(geometry2, geometry1, spatialRef);
}

4.8 Crosses(穿过)

4.8.1 定义

如果两个几何对象的内部相交,但既不完全相同,也没有一个包含另一个,则它们穿过。通常用于线与线或线与面的关系。

4.8.2 API

public class CrossesOperator : IBinaryGeometryOperator<bool>
{public static CrossesOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.8.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 两条交叉的线
var line1 = new Polyline();
line1.AddPath(new List<Point>
{new Point(0, 50),new Point(100, 50)  // 水平线
});var line2 = new Polyline();
line2.AddPath(new List<Point>
{new Point(50, 0),new Point(50, 100)  // 垂直线
});bool crosses = GeometryEngine.Crosses(line1, line2);  // true// 线穿过多边形
var polyline = new Polyline();
polyline.AddPath(new List<Point>
{new Point(-10, 50),new Point(110, 50)  // 穿过多边形
});var polygon = new Polygon();
polygon.AddRing(new List<Point>
{new Point(0, 0),new Point(100, 0),new Point(100, 100),new Point(0, 100),new Point(0, 0)
});bool lineCrossesPoly = GeometryEngine.Crosses(polyline, polygon);  // true

4.9 Touches(接触)

4.9.1 定义

如果两个几何对象仅在边界上有共同点,而内部不相交,则它们接触。

4.9.2 API

public class TouchesOperator : IBinaryGeometryOperator<bool>
{public static TouchesOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.9.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 两个相邻的多边形
var poly1 = new Polygon();
poly1.AddRing(new List<Point>
{new Point(0, 0),new Point(50, 0),new Point(50, 100),new Point(0, 100),new Point(0, 0)
});var poly2 = new Polygon();
poly2.AddRing(new List<Point>
{new Point(50, 0),   // 共享边界new Point(100, 0),new Point(100, 100),new Point(50, 100), // 共享边界new Point(50, 0)
});bool touches = GeometryEngine.Touches(poly1, poly2);  // true(共享边界)// 点在多边形边界上
var boundaryPoint = new Point(0, 50);  // 在 poly1 的左边界上
bool pointTouches = GeometryEngine.Touches(boundaryPoint, poly1);  // true

4.10 Overlaps(重叠)

4.10.1 定义

如果两个相同维度的几何对象相交,但既不完全相同,也没有一个完全包含另一个,则它们重叠。

4.10.2 API

public class OverlapsOperator : IBinaryGeometryOperator<bool>
{public static OverlapsOperator Instance { get; }public bool Execute(Geometry geometry1, Geometry geometry2, SpatialReference? spatialRef = null);
}

4.10.3 使用示例

using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;// 两个部分重叠的多边形
var poly1 = new Polygon();
poly1.AddRing(new List<Point>
{new Point(0, 0),new Point(60, 0),new Point(60, 60),new Point(0, 60),new Point(0, 0)
});var poly2 = new Polygon();
poly2.AddRing(new List<Point>
{new Point(40, 40),new Point(100, 40),new Point(100, 100),new Point(40, 100),new Point(40, 40)
});bool overlaps = GeometryEngine.Overlaps(poly1, poly2);  // true// 两个包络矩形重叠
var env1 = new Envelope(0, 0, 50, 50);
var env2 = new Envelope(25, 25, 75, 75);
bool envOverlaps = GeometryEngine.Overlaps(env1, env2);  // true

4.11 空间关系矩阵

4.11.1 关系总结

下表显示了各种空间关系之间的逻辑关系:

条件 Disjoint Intersects Contains Within Touches Overlaps Crosses Equals
A ∩ B = ∅ ✓
A ∩ B ≠ ∅ ✓
B ⊆ A ✓ ✓
A ⊆ B ✓ ✓
仅边界相交 ✓ ✓
部分内部重叠 ✓ ✓
线性穿过 ✓ ✓
A = B ✓ ✓ ✓ ✓

4.11.2 互斥关系

// Disjoint 和 Intersects 互斥
Disjoint(A, B) = !Intersects(A, B)// Contains 和 Within 是逆关系
Contains(A, B) = Within(B, A)

4.12 最佳实践

4.12.1 性能优化

// 1. 先用包络矩形快速过滤
var queryEnvelope = new Envelope(100, 100, 200, 200);
var candidates = allGeometries.Where(g => g.GetEnvelope().Intersects(queryEnvelope));// 2. 再进行精确测试
var results = candidates.Where(g => GeometryEngine.Intersects(g, queryPolygon)).ToList();

4.12.2 常见错误

// ❌ 错误:直接精确测试大量几何对象
var results = allGeometries.Where(g => GeometryEngine.Contains(polygon, g))  // 性能差.ToList();// ✅ 正确:先包络过滤
var polygonEnvelope = polygon.GetEnvelope();
var results = allGeometries.Where(g => polygonEnvelope.Intersects(g.GetEnvelope())).Where(g => GeometryEngine.Contains(polygon, g)).ToList();

4.12.3 选择正确的关系测试

需求 推荐操作符
检查点是否在区域内 Contains
检查两个区域是否有交集 Intersects
查找最近的对象 Distance
检查两个对象是否相同 Equals
检查线是否穿过区域 Crosses
检查区域是否相邻 Touches

4.13 小结

本章详细介绍了 geometry-api-net 提供的 9 种空间关系操作符:

  1. Contains:测试包含关系,使用光线投射算法
  2. Intersects:测试是否有共同部分
  3. Distance:计算最短距离
  4. Equals:测试空间相等性
  5. Disjoint:测试分离关系(Intersects 的逆)
  6. Within:测试在内部关系(Contains 的逆)
  7. Crosses:测试穿过关系
  8. Touches:测试接触关系
  9. Overlaps:测试重叠关系

这些操作符是进行空间分析的基础,在下一章中我们将学习几何运算操作符,它们可以生成新的几何对象。

相关新闻

  • 01-项目概述与框架理念
  • 2026年数控机床主轴轴承厂家推荐 磨床主轴轴承、车床轴承、铣床轴承、动力头轴承源头厂家
  • day7敏捷冲刺

最新新闻

  • AgentV-RL:用智能体验证器破解强化学习奖励设计难题
  • FCPO算法:轻量级混合群智能策略破解昂贵黑箱优化难题
  • 题解:AcWing 396 矿场搭建
  • 2026成都黄金回收实战经验!最新门店排行新鲜出炉 - 奢品小当家
  • 2026杭州装修公司深度剖析:基于多维度数据评选的六家优质榜单 - 资讯报道
  • 微信投票制作步骤分享,一分钟学会小白也能搞定! - 微信投票小程序

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号