update:
Dec 30 2025 点在多边形内概要
写在前面
简单实现:
求线段AP在线段AB上的投影长度; 求点P在线段AB上的投影点的坐标; 判断点P的投影点是否在线段AB内; 求∠PAB的角度值; 判断∠PAB是锐角、直角,还是钝角。 求向量AP和AB组成的平行四边形的面积; 若有另外一点Q,判断向量PQ与AB是否平行; 判断点P在向量AB的左侧还是右侧。方法有三种,向量法可以求的答案多、此外还有面积法和待定系数求解法(设pp的坐标为x,y,直接推导)
#include<iostream>#include<algorithm>#include<cmath>#include<thread>#include<mutex>#include<iostream>#include<glog/logging.h>usingnamespacestd;intmain(intargc,char*argv[]){google::InitGoogleLogging(argv[0]);google::SetStderrLogging(google::GLOG_ERROR);FLAGS_colorlogtostderr=true;FLAGS_logtostderr=true;FLAGS_minloglevel=0;// questionsfloatdistance_PtoAB=0;pair<int,int>a=make_pair(1,1);pair<int,int>b=make_pair(2,4);pair<int,int>p=make_pair(3,3);pair<int,int>ap=make_pair(2,2);pair<int,int>ab=make_pair(1,3);pair<int,int>bp=make_pair(1,-1);pair<int,int>ba=make_pair(-1,-3);floatAP_l=sqrt(ap.first*ap.first+ap.second*ap.second);floatBP_l=sqrt(bp.first*bp.first+bp.second*bp.second);floatAB_l=sqrt(ab.first*ab.first+ab.second*ab.second);floatthetaPAB_cos=(ap.first*ab.first+ap.second*ab.second)/AP_l/AB_l;floatthetaABP_cos=(ba.first*bp.first+ba.second*bp.second)/BP_l/AB_l;LOG(INFO)<<"thetaPAB_cos: "<<thetaPAB_cos;LOG(INFO)<<"thetaABP_cos: "<<thetaABP_cos;cout<<"thetaPAB: "<<acos(thetaPAB_cos)<<endl;if(thetaPAB_cos<=0){distance_PtoAB=sqrt(ap.first*ap.first+ap.second*ap.second);if(thetaPAB_cos!=0){cout<<"PAB is obtuse angle"<<endl;cout<<"Project of P is outside AB"<<endl;}}elseif(thetaABP_cos<=0){distance_PtoAB=sqrt(bp.first*bp.first+bp.second*bp.second);if(thetaABP_cos!=0){cout<<"PAB is acute angle"<<endl;cout<<"Project of P is outside AB"<<endl;}}else{distance_PtoAB=(ap.first)*sqrt((1-thetaPAB_cos*thetaPAB_cos));cout<<"PAB is acute angle"<<endl;cout<<"Project of P(PP) is inside AB"<<endl;// cal unit vector of ABpair<float,float>AB_unitvector(ab.first/AB_l,ab.second/AB_l);LOG(INFO)<<"AB_unitvector: "<<AB_unitvector.first<<","<<AB_unitvector.second;floatAPP_l=(ap.first*ab.first+ap.second*ab.second)/AB_l;pair<float,float>APP(APP_l*AB_unitvector.first,APP_l*AB_unitvector.second);pair<float,float>PP(APP.first-a.first,APP.second-a.second);cout<<"and the PP is "<<PP.first<<","<<PP.second<<endl;}std::cout<<"distance_PtoAB: "<<distance_PtoAB<<std::endl;google::ShutdownGoogleLogging();}sin相关
求向量AP和AB组成的平行四边形的面积; 若有另外一点Q,判断向量PQ与AB是否平行; 判断点P在向量AB的左侧还是右侧。问题比较简单 通过观察叉乘的结果就可以判断
判断点P在向量AB的左侧还是右侧: 用叉乘,顺逆时针即可判断。 向量BA和PA做叉乘,右手螺旋,纸外为正。从BA到PA。
cross = (B − A) × (P − A) = (Bx−Ax)(Py−Ay) − (By−Ay)(Px−Ax)
cross > +EPS ⇒ P 在 AB 的左侧(逆时针)
cross < −EPS ⇒ P 在 AB 的右侧(顺时针)
|cross| ≤ EPS ⇒ 共线
向量 PQ 与 AB 是否平行:仍用叉乘判断两向量的“面积”为 0。
crossABPQ = (B−A) × (Q−P)
|crossABPQ| ≤ EPS ⇒ 平行(含同向/反向)
方向区分:dot = (B−A)·(Q−P);dot > 0 同向,dot < 0 反向
判定点在多边形内
在工作中涉及到了雷达的遮蔽问题,某个细节需要能判定点在多边形内(实际上是四个角落雷达,设定了重叠区域和非重叠区域,划分了多边形,同时对于object 通过设置代表了是那个传感器看到的bitmask,此时需要判定一下object是否在fov和探测距离分段划分好的多边形内)
工程细节不论,概要是:
1 多边形顶点要够 代码里设定为大于3
2 临接多边形顶点遍历 并且排除水平可能性
3 点与边的判断 要点是水平向右以pt点为起点做射线 1 pt点的y在边的顶点y中间 2 插值法看到 pt点x小于交点x 同时满足1 和2,设定相交一次,射线遍历多边形所有边后,相交次数为偶数则点在多边形外 反之在内。0 这里也是算不在
if(((vi_y>pt_y)!=(vj_y>pt_y))&&(pt_x<(vj_x-vi_x)*(pt_y-vi_y)/y_diff+vi_x)){inside=!inside;}AI 再此归纳 简单的计算几何问题
8个向量问题的求解方法
设坐标:\vec{A} = (x_A, y_A),\vec{B} = (x_B, y_B),\vec{P} = (x_P, y_P)
① 线段AP在AB上的投影长度
思路:投影长度 = AP 在 AB 方向上的标量投影
t = \frac{\vec{AP} \cdot \vec{AB}}{|\vec{AB}|} = \frac{(P_x - A_x)(B_x - A_x) + (P_y - A_y)(B_y - A_y)}{\sqrt{(B_x - A_x)^2 + (B_y - A_y)^2}}
⚠️ 这里 t 可正可负,表示投影方向与 AB 相同或相反。若只求"长度"取绝对值 |t|。
② 点P在AB上的投影点坐标
思路:参数 t = \dfrac{\vec{AP} \cdot \vec{AB}}{\vec{AB} \cdot \vec{AB}}(即 0 \le t \le 1 时投影在线段内)
\vec{H} = \vec{A} + t \cdot \vec{AB}
即:
H_x = A_x + t(B_x - A_x)
H_y = A_y + t(B_y - A_y)
③ 判断投影点是否在线段AB内
思路:用上面的 t 值判断
0 \le t \le 1 \quad \iff \quad \text{投影点在线段AB上}
即判断:
0 \le \vec{AP} \cdot \vec{AB} \le |\vec{AB}|^2
④ ∠PAB的角度值
思路:用点乘公式求夹角
\cos\angle PAB = \frac{\vec{AP} \cdot \vec{AB}}{|\vec{AP}||\vec{AB}|}
\angle PAB = \arccos\left(\frac{\vec{AP} \cdot \vec{AB}}{|\vec{AP}||\vec{AB}|}\right)
⑤ 判断∠PAB是锐角/直角/钝角
思路:只看点乘符号,无需算角度!
条件 结论
\vec{AP} \cdot \vec{AB} > 0 锐角
\vec{AP} \cdot \vec{AB} = 0 直角
\vec{AP} \cdot \vec{AB} < 0 钝角
因为 \cos\theta 的正负完全由点乘决定。
⑥ 向量AP和AB组成的平行四边形面积
思路:二维叉乘的模 = 面积
S = \left| \vec{AP} \times \vec{AB} \right| = \left| (P_x - A_x)(B_y - A_y) - (P_y - A_y)(B_x - A_x) \right|
二维叉乘退化为标量(行列式值),取绝对值即为平行四边形面积。
⑦ 判断PQ与AB是否平行
思路:叉乘为 0 ⟺ 平行
\vec{PQ} \times \vec{AB} = 0 \quad \iff \quad (Q_x - P_x)(B_y - A_y) - (Q_y - P_y)(B_x - A_x) = 0
或者用比例判断:
\frac{Q_x - P_x}{B_x - A_x} = \frac{Q_y - P_y}{B_y - A_y}
(注意处理分母为 0 的情况)
⑧ 判断点P在向量AB的左侧还是右侧
思路:二维叉乘的符号决定左右
cross = \vec{AB} \times \vec{AP} = (B_x - A_x)(P_y - A_y) - (B_y - A_y)(P_x - A_x)
cross 符号 结论
0 P 在 AB 的左侧(逆时针)
= 0 P 在 AB 直线上
< 0 P 在 AB 的右侧(顺时针)
🔑 总结公式速查
点乘: AP · AB = dx1dx2 + dy1dy2 → 投影、角度、左右判断
叉乘: AP × AB = dx1dy2 - dy1dx2 → 面积、平行、左右判断
参数 t:t = (AP·AB) / |AB|² → 投影点、是否在线段内
💡 核心技巧:几乎所有问题都归结为点乘和叉乘两个运算,掌握这两个工具就能解决全部8个问题。