point_in_polygon判断点是否在多边形内需区分严格包含与边界允许:严格包含要求所有点严格在内部(不触边),推荐非零环绕数算法并配合浮点容差;gis等场景若允许边界重合,需配置容差或结合奇偶规则与闭合判断。

用 point_in_polygon 判断点是否在多边形内是基础
判断包含关系本质是:若多边形 A 的所有顶点都在多边形 B 内部(且 B 的所有顶点都不在 A 内部),则 A ⊂ B;反过来同理。但直接套用点在多边形内的判断还不够——必须处理边界情况。
常见错误是只用射线法(ray casting)判点,却忽略「点恰好落在 B 的边上」算不算「在内部」。标准几何包含(strict containment)通常要求**所有点严格在内部**,即不接触边界。若业务允许边界重合(如 GIS 中的“contains”语义),需额外配置容差或改用奇偶规则+闭合判断。
-
point_in_polygon推荐用非零环绕数(winding number)算法,比射线法更鲁棒,尤其对自相交多边形 - 浮点比较必须带容差,例如
abs(x) ,不能直接写 <code>== 0 - 若多边形顶点顺序不一致(顺/逆时针混用),
winding_number符号会翻转,导致误判——先统一用compute_orientation校验并归一化方向
凸多边形可用分离轴定理(SAT)快速排除
对两个凸多边形,SAT 是 O(n+m) 的高效方法:若存在一条直线能分开二者,则不相交;若所有潜在分离轴(即每条边的法向量)上投影重叠,则可能相交或包含。但 SAT 本身不直接给出「包含」结论,需结合点测试补全逻辑。
实际中,先用 SAT 快速判断是否「不相交」或「明显不包含」,再对剩余情况调用点测试,能避免大量冗余计算。
- 凸多边形的分离轴数量 = 边数之和,每条轴做投影只需 dot 积,无开方无分支
- 若 A 投影完全落在 B 投影内,且 B 投影不完全落在 A 内 → A 很可能被 B 包含(仍需验证顶点)
- SAT 对凹多边形失效,强行使用会漏判;此时必须退回到逐点 + 边相交检测
处理凹多边形必须检查边相交与顶点位置双重条件
仅验证顶点是否在对方内部是不够的:一个凹多边形可能所有顶点都在另一个内部,但中间“凹陷”部分穿出边界(即边与对方边界相交)。所以必须额外检测 A 的每条边是否与 B 的任意边相交。
典型反例:B 是矩形,A 是“U”形凹多边形,开口朝外,三个顶点在矩形内,但底边横跨矩形外部——此时 A 不被 B 包含,但仅靠点测试会误判。
- 边相交检测用参数化线段求交,避免除零;推荐用
ccw(counter-clockwise winding)辅助判断是否规范相交 - 若发现 A 的任一边与 B 的任一边有**内部交点**(非端点重合),则 A 不被 B 包含
- 端点重合(如 A 顶点恰为 B 顶点)需按业务定义:GIS 中常视为边界接触,不破坏包含;图形学中可能要求严格内部,此时需额外剔除
OpenCV 和 Boost.Geometry 的现成方案怎么选
自己实现易出错,优先考虑成熟库。但要注意它们对「包含」的定义差异:
- OpenCV 的
pointPolygonTest返回 >0 表示内部,=0 表示边上,cv::convexHull 只支持凸包,对凹多边形需先 triangulate 或用findContours配合matchShapes间接推断 - Boost.Geometry 的
within(A, B)默认采用 OGC 精确语义:A 的所有点属于 B 的内部或边界,且 A 的内部至少有一个点;若要 strict containment,得手动过滤掉边界接触点 - 两者都依赖输入多边形为简单多边形(无自交);若原始数据可能自交,必须先调用
boost::geometry::correct或 OpenCV 的approxPolyDP预处理
真正容易被忽略的是拓扑一致性:很多 bug 源于多边形首尾点未闭合、重复点未去重、或顶点顺序在读取时被意外翻转——这些不会报错,但会让 within 或 pointPolygonTest 返回反直觉结果。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











