判断点在凸多边形内需所有叉积同号(≥0或≤0),前提是顶点严格顺/逆时针有序;叉积为0仅说明共线,须额外判断是否在线段范围内,且须用eps处理浮点误差。

用叉积符号判断点与每条边的相对位置
核心思路是:对凸多边形的每条有向边 edge[i] → edge[i+1],计算点 P 相对于该边的叉积符号。若所有叉积同号(全 ≥ 0 或全 ≤ 0,取决于顶点顺序),则点在内部或边上;否则在外。
关键前提是顶点必须按顺时针或逆时针顺序排列(不能乱序)。常见错误是传入无序顶点数组,导致叉积符号杂乱,结果完全不可靠。
实操建议:
- 先用
std::is_sorted或手动检查顶点是否构成单调环绕(如用atan2算极角排序),但更稳妥的是预处理时确保输入是合法凸包(例如用convex_hull_graham生成) - 叉积公式为:
(v1.x * v2.y - v1.y * v2.x),其中v1 = edge[i+1] - edge[i],v2 = P - edge[i] - 使用
double计算叉积,避免整数溢出;比较时用eps = 1e-9处理浮点误差,不要直接写== 0
处理边界情况:点恰好落在边上或顶点上
叉积为 0 表示点共线于某条边,但不等于就在多边形内——还需进一步判断是否在线段范围内。这是最容易漏掉的坑。
实操建议:
- 当某次叉积绝对值 eps 时,不能直接返回 false,要额外做线段包含检测:
dot(P - edge[i], P - edge[i+1]) (即向量夹角 ≥ 90°,说明投影落在端点之间) - 若点与某个顶点距离 eps,可提前返回 true;但不要用欧氏距离平方开方,改用
(P.x - v.x)*(P.x - v.x) + (P.y - v.y)*(P.y - v.y) - 若多边形退化(三点共线、边长为 0),需在调用前用
std::unique去重并跳过零长边,否则叉积恒为 0 导致误判
性能优化:提前退出 + 缓存边向量
最坏情况要算 n 次叉积,但实际中多数点都在外部,越早发现异号叉积越快返回。同时重复构造向量会拖慢速度。
实操建议:
- 循环中一旦发现当前叉积符号与首个非零叉积符号相反,立即 return false;不要等全部算完
- 把边向量
edge[i+1] - edge[i]预存在std::vector<:pair>></:pair>中,避免每次循环重复减法运算 - 若需高频调用(如光栅化、碰撞检测),可将多边形顶点转为
std::array固定大小存储,并用constexpr预计算边向量(C++20 起支持)
完整函数骨架与典型错误
一个健壮的实现必须同时覆盖顶点顺序、浮点误差、退化边、空/单点输入。下面这个片段能跑通大多数场景,但注意它不处理自相交多边形(那已不是凸多边形):
bool pointInConvexPolygon(const std::vector<:pair>>& poly,
double px, double py, double eps = 1e-9) {
if (poly.size() eps) has_pos = true;
else if (cross <p>典型错误包括:忘记取模 <code>(i+1)%n</code> 导致最后一条边丢失;用 <code>int</code> 存坐标引发截断;未检查 <code>poly.empty()</code> 导致 <code>poly[0]</code> 越界;把 <code>cross > 0</code> 写成 <code>>= 0</code> 导致边界点被排除。</p>
<p>真正难的不是算法本身,而是如何让这段逻辑在嵌入式设备上不崩、在并发场景下不因浮点环境差异翻车、以及当美术导出的“凸多边形”其实带锯齿顶点时怎么优雅降级——这些细节比叉积公式重要得多。</p></:pair>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











