GraphicsPath.IsVisible 是判断点是否在多边形内的最简方案,自动处理自相交、孔洞及填充规则;需注意坐标系Y轴方向、跨平台限制及顶点闭合顺序。
用 GraphicsPath.IsVisible 判断点是否在多边形内(最简方案)
多数业务场景下,不需要手写射线法或叉积判断——system.drawing.drawing2d.graphicspath 已封装可靠实现,且自动处理自相交、孔洞、奇偶/非零填充规则。
实操建议:
- 构造
GraphicsPath时用AddPolygon或逐点AddLine,确保顶点顺序闭合(首尾不必重复) - 调用
IsVisible(x, y)前,确认路径未被销毁;若频繁调用,复用同一GraphicsPath实例 - 注意:该方法依赖 GDI+ 坐标系(Y 轴向下),若数据来自地理坐标或 OpenGL 等 Y 向上系统,需先翻转 Y
- 不支持
net6.0+的Microsoft.NETCore.App默认部署(因System.Drawing在 Linux/macOS 上需额外安装libgdiplus)
手写射线交叉法(Ray Casting)绕过 System.Drawing 依赖
当项目禁用 System.Drawing(如纯 .NET 6+ Web API、AOT 编译、容器无图形库),或需跨平台稳定行为时,应自行实现。
常见错误现象:IsInsidePolygon(1.5, 2.0) 返回 false,但肉眼明显在内部——大概率是顶点未按顺时针/逆时针一致排序,或浮点精度导致射线恰好穿过顶点。
实操建议:
- 使用整数或
double表示坐标,避免float累积误差 - 射线选水平向右方向,对每个边做“是否与射线相交且交点在点右侧”判断
- 顶点共线、射线过顶点时,统一约定:仅当边的**上端点**严格高于点 Y,且**下端点** ≤ 点 Y 时才计数(排除重复交点)
- 示例关键逻辑:
bool intersect = (p1.Y > y) != (p2.Y > y) && x
WKT / GeoJSON 多边形解析后判断(GIS 场景)
若输入是 "POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" 这类文本,别直接正则拆——WKT 可能含 Z/M 坐标、嵌套环(外环+内环)、多部分(MULTIPOLYGON)。
实操建议:
- 用
NetTopologySuite(推荐)或GeoAPI解析,它自动标准化环方向、校验有效性、处理孔洞 - 解析后调用
geometry.Contains(point),而非手算;Contains和Intersects行为不同:前者要求点严格在内部(不含边界),后者包含边界 - 注意:NTS 默认使用平面欧氏几何,若坐标是经纬度(WGS84),需先投影(如 WebMercator)再计算,否则距离/包含关系失真
- 性能影响:NTS 构造
Geometry有开销,高频调用建议缓存解析结果
边界点判定模糊时的取舍策略
“点刚好落在边上”算不算“在多边形内”,没有标准答案——取决于业务。地图围栏通常要包含边界,碰撞检测可能要求严格内部。
实操建议:
-
GraphicsPath.IsVisible默认采用非零环绕规则,边界点返回true;但若路径用FillMode.Alternate,行为可能不同 - 手写射线法中,可通过微扰点坐标(如
x + 1e-9)规避边界争议,但会引入新误差 - NTS 提供
geometry.Covers(point)(含边界)和geometry.Contains(point)(不含),比布尔运算更语义清晰 - 最容易被忽略的是:所有算法对退化多边形(三点共线、面积为零)行为不一致,上线前务必用
POINT(0 0)和POLYGON((0 0, 0 0, 0 0))类用例压测











