核心思路是:凸多边形所有内点必位于每条有向边的同一侧,因此计算点对每条边的叉积符号,若全部一致(全≥0或全≤0),则点在内部或边界上;该方法稳定、不依赖顶点顺逆序,且无浮点退化风险。

凸多边形点在内判断的核心思路是什么?
凸多边形有个关键性质:所有内点都在每条边的同一侧(比如左侧)。所以只要对每条边计算点相对于该边的有向面积符号(即叉积符号),全部一致就说明点在内部或边界上。这是最稳定、不依赖顶点顺序(顺/逆时针)且无浮点退化风险的方案。
- 叉积
cross(o, a, b)计算的是向量oa与ob的二维叉积,即(a.x - o.x) <em> (b.y - o.y) - (a.y - o.y) </em> (b.x - o.x) - 若所有边
edge[i] → edge[i+1]对应的cross(edge[i], edge[i+1], point)符号相同(≥0 或 ≤0),则点在内部或边上 - 严格内部需全部 ≠ 0;允许边界则用 ≥0 或 ≤0 判断
如何写一个健壮的 C++ 函数判断点是否在凸多边形内?
直接用叉积逐边判断,避免角度计算、射线法(易出边界问题)或重心坐标(对凸性无额外收益)。注意三点:
- 多边形顶点必须按顺序存储(顺时针或逆时针均可,但需一致)
- 使用
long long或double防止叉积整数溢出(尤其坐标范围大时) - 边界处理:若需排除边界,把
sign == 0视为失败;否则允许sign >= 0(假设多边形逆时针)
bool isPointInConvexPolygon(const vector<pair<double, double>>& poly, double px, double py) {
int n = poly.size();
if (n < 3) return false;
int sign = 0;
for (int i = 0; i < n; ++i) {
auto& p1 = poly[i];
auto& p2 = poly[(i + 1) % n];
double cross = (p2.first - p1.first) * (py - p1.second) - (p2.second - p1.second) * (px - p1.first);
if (cross == 0.0) continue; // 在边上,按需求决定是否接受
int curSign = (cross > 0) ? 1 : -1;
if (sign == 0) sign = curSign;
else if (sign != curSign) return false;
}
return true; // 所有非零叉积同号,或全为 0(退化为线段,但输入保证是凸多边形)
}常见错误和坑点有哪些?
-
cross 参数顺序写反:比如误写成 (px - p1.first) * (p2.second - p1.second) - ...,会导致符号翻转,结果全错
- 忘记取模:遍历边时
i+1 超出数组范围,没写 (i + 1) % n,最后一条边丢失
- 浮点精度陷阱:用
== 0.0 判断共线不可靠,实际应加 epsilon(如 abs(cross) < 1e-9),但凸多边形判断中若仅需“是否严格在内”,可直接用 > 0 / < 0 避开
- 把非凸多边形当凸的用:该方法只适用于凸多边形,对凹多边形会漏判或误判,不加校验直接套用很危险
性能和适用场景怎么权衡?
- 时间复杂度 O(n),对凸多边形已是理论最优(必须检查每条边)
- 比射线法更稳:无奇偶计数误差、不依赖起始方向、不卡水平边
- 比二分查找(如切片法)更通用:不要求顶点极角有序(虽然凸多边形通常满足,但你未必能保证输入顺序)
- 如果多边形固定且查询频繁,可预处理成极角排序 + 二分,但单次判断没必要——直接叉积循环更清晰、更不易错
cross 参数顺序写反:比如误写成 (px - p1.first) * (p2.second - p1.second) - ...,会导致符号翻转,结果全错i+1 超出数组范围,没写 (i + 1) % n,最后一条边丢失== 0.0 判断共线不可靠,实际应加 epsilon(如 abs(cross) < 1e-9),但凸多边形判断中若仅需“是否严格在内”,可直接用 > 0 / < 0 避开- 时间复杂度 O(n),对凸多边形已是理论最优(必须检查每条边)
- 比射线法更稳:无奇偶计数误差、不依赖起始方向、不卡水平边
- 比二分查找(如切片法)更通用:不要求顶点极角有序(虽然凸多边形通常满足,但你未必能保证输入顺序)
- 如果多边形固定且查询频繁,可预处理成极角排序 + 二分,但单次判断没必要——直接叉积循环更清晰、更不易错
真正容易被忽略的是:这个方法依赖“凸”这个前提本身。一旦多边形因数值误差或构造逻辑轻微凹陷,cross 符号就会突变,结果失效。所以生产环境建议加一句简单凸性校验(比如检查所有相邻三顶点叉积同号),或者明确文档注明“调用方须确保输入为凸”。


















