点p在三角形abc内部当且仅当其位于有向边ab、bc、ca的同一侧,通过计算叉积cross(ab,ap)、cross(bc,bp)、cross(ca,cp)的符号是否同号(全≥0或全≤0)判断,严格内部要求三者同号且非零。

用叉积符号判断点与三角形边的相对位置
核心思路是:点 P 在三角形 A-B-C 内部,当且仅当它在三条有向边 AB、BC、CA 的同一侧(都左侧或都右侧)。这可以通过二维叉积的符号统一判断。
对任意两点 P1、P2 和测试点 P,计算向量 P1→P2 与 P1→P 的叉积:cross = (P2.x - P1.x) * (P.y - P1.y) - (P2.y - P1.y) * (P.x - P1.x)
这个值的正负号表示 P 在有向线段 P1P2 的哪一侧(正:左侧;负:右侧;零:共线)。
实操建议:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 按固定顺序(如逆时针)传入三角形顶点,比如
A、B、C,然后依次检查cross(AB, AP)、cross(BC, BP)、cross(CA, CP) - 若三者同号(全 ≥ 0 或全 ≤ 0),则点在内部或边界上;若要求严格内部,需三者同号且全 ≠ 0
- 注意浮点比较:避免直接用
== 0,改用abs(cross) 判断是否共线
处理退化三角形和浮点精度问题
当三角形三点共线(面积为 0)时,叉积恒为 0,所有点都会被误判为“在内部”。这是真实项目中最容易漏掉的边界情况。
实操建议:
- 先快速检测三角形是否退化:计算面积绝对值
abs(cross(AB, AC)) / 2,若小于eps(如1e-9),直接返回false(或按业务定义未定义行为) - 叉积计算全程用
double,避免float累积误差;整数坐标也建议转double后运算 - 不要依赖
std::signbit或std::copysign,用cross > eps、cross 、<code>abs(cross) 三区间判断更稳妥
用重心坐标法做验证或需要插值时的替代方案
如果后续还要算纹理坐标、深度插值或颜色混合,重心坐标法更自然——它直接给出点相对于三角形三个顶点的权重 (u, v, w),满足 u + v + w = 1 且全部 ≥ 0 表示在内部(含边界)。
实操建议:
- 解方程组即可:设
P = u*A + v*B + w*C,其中w = 1 - u - v,代入后解二元一次方程组求u、v - 分母是三角形有向面积的 2 倍:
denom = cross(B-A, C-A);分子分别是cross(P-A, C-A)和cross(B-A, P-A) - 相比叉积法,重心坐标法多 2 次除法和若干加减,但结果更稳定,且天然支持插值需求
别忽略坐标系和顶点顺序的影响
叉积符号取决于坐标系朝向。在 OpenGL/D3D 默认的右手系窗口坐标中,Y 向下,此时“逆时针”顶点顺序对应的是顺时针几何方向——如果不小心混用,符号判断会翻转。
实操建议:
- 统一使用数学标准坐标系(Y 向上)做判断逻辑;若输入是屏幕坐标(Y 向下),要么预翻转 Y 值,要么在叉积公式里把 y 差值取反
- 不要假设用户给的三角形顶点是逆时针;可先用
cross(B-A, C-A)判断原始朝向,再决定“同号”是指全正还是全负 - 调试时打印出三个叉积值,比单看布尔结果更容易定位是某条边判断异常,还是整体顺序错了
真正难的不是公式本身,而是不同坐标系、不同数据来源(模型导出、鼠标坐标、GPU 输出)带来的隐式方向不一致。每次接入新数据源,都值得花 30 秒验证一个已知在内部的点是否被正确识别。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










