作者:henu_wxj
链接:https://blog.nowcoder.net/n/16a7f7a8cb4042278aacb509d205ce69
来源:牛客网
点的定位
点的定位属于几何查找,是计算几何中的一个重要的问题。其包括点在三角形内外,多边形内外判断,平面剖分中的位置等。
关于出现在这篇文章中但没有给出的自定义函数,如:
判断点是否在线上:
我们可以用刚刚我们提到的叉积重要性质,即:两向量叉积为0,说明两向量在一条直线上。因此:
设点Q在线段
1.
2.Q
![d8dd9788bc11a4d468a1a7b3218bf1f3.png](https://img-blog.csdnimg.cn/img_convert/d8dd9788bc11a4d468a1a7b3218bf1f3.png)
(画出来大概是这样)
Code:
int OnLine(Point P1,Point P2,Point Q){
if((Q.x-P1.x)*(P2.y-P1.y)==(P2.x-P1.x)*(Q.y-P1.y)){
if(min(P1.x,P2.x)<=Q.x&&Q.x<=max(P1.x,P2.x)
&&min(P1.y,P2.y)<=Q.y&&Q.y<=max(P1.x,P2.y)){
return 1;
}
}return 0;
}
判断点在三角形的内外:
点在平面内与三角形三个顶点中任意两点构成三个三角形。可以通过计算这三个三角形的面积和与原三角形面积来比较判断点是否在三角形内。
设
Code:
int InTriangle(Triangle Tri,Point P){
V AB,AC,PA,PB,PC;
AB.start=Tri.A;AB.end=Tri.B;
AC.start=Tri.A;AC.end=Tri.C;
PA.start=P;PA.end=Tri.A;
PB.start=P;PB.end=Tri.B;
PC.start=P;PC.end=Tri.C;
double Sabc=fabs(CroMul(AB,AC));
double Spab=fabs(CroMul(PA,PB));
double Spac=fabs(CroMul(PA,PC));
double Spbc=fabs(CroMul(PB,PC));
if(Spab+Spac+Spbc==Sabc) return 1;
return 0;
}
判断点在多边形的内外:
点在几何图形内外的判断中,多边形的判断是通用情况,分三种方法:1.扫描法,2.叉积判别法,3.角度和判断法。
1.扫描法
设点
![877533d8b0b3440260f05fc93a18d96e.png](https://img-blog.csdnimg.cn/img_convert/877533d8b0b3440260f05fc93a18d96e.png)
首先以
推论:当射线与多边形的交点数目是奇数时,
![d6817e14126f2ddffefaa95943710cce.png](https://img-blog.csdnimg.cn/img_convert/d6817e14126f2ddffefaa95943710cce.png)
我们用一个长的平行于
发现有一些情况要分类讨论,可以根据分类情况做出一些限制,例如:
1.多边形的水平边不做考虑。
2.对于与多边形顶点相交,如果该顶点是其所属边上纵坐标比较大的顶点,则计数,否则忽略。
3.对于
Code:
int InPolygonScan(Point Q){//扫描法
int counter=0;double xinters;Point P1,P2;
P1=Poly[0];
for(int i=1;i<=n;++i){//遍历所有的点
P2=Poly[i%n];
if(OnLine(P1,P2,Q)) return 1;//在线上
if(Q.y>min(P1.y,P2.y)&&Q.y<=max(P1.y,P2.y)){//在线段内
if(Q.x<=max(P1.x,P2.x)){
if(P1.y!=P2.y){
xinters=(Q.y-P1.y)*(P2.x-P1.x)/(P2.y-P1.y)+P1.x;
if(P1.x==P2.x||Q.x<=xinters) counter++;//符合要求
}
}
}P1=P2;
}
if(counter%2==0) return 0;
return 1;
}
int main(){
int t=0;Point Q;
while(cin>>n){
if(n==0) break;
if(t++>0) cout<<endl;
cout<<"Problem "<<t<<":"<<endl;
cin>>m;
for(int i=0;i<n;++i){
cin>>Poly[i].x>>Poly[i].y;
}
for(int i=0;i<m;++i){
cin>>Q.x>>Q.y;
if(InPolygonScan(Q)) cout<<"Within"<<endl;
else cout<<"Outside"<<endl;
}
}
}
2.叉乘判别法(只适用于凸多边形)
一个凸多边形,每条边都将整个平面划分成为左右两边。设这个多边形的边数为n,选一条边作为1号边,然后按照顺时针或者逆时针的顺序给每条边进行编号。
连接第i条边的第一个端点
除第一条边外,都与前一次运算得到的叉积做乘积。如果为正,继续判断,直到遍历所有的边。若全部满足,则证明点在多边形内,否则点在多变形外。
Code:
int InPolygonCroPro(Point Q){
//现在已经从选择一个点,逆时针||顺时针方向排好序了
int i;double pre,now;
for(int i=0;i<n;++i){//逆时针||顺时针遍历所有的点
Point P1=Poly[i],P2=Poly[i+1];
V v1=V(P1,Q),v2=V(P1,P2);
now=CroMul(v1,v2);
if(i>0){
if(pre*now<0) return 0;
}pre=now;
}return 1;
}
3.角度和的判断法(适用于任意多边形,注意精度损失)
对于平面三角形来说,连接多边形内点与多边形所有顶点所形成的所有角的角度和在要求精度范围内应该=360°,如果大于||小于360°,则证明点不在多边形中。
Code:
int InPolygonAngle(Point Q){//角度判别法
double Angle=0;
realPointList::interator iter1.begin();
for(realPointList::interator iter2=(iter1+1);iter2<Points.end();++iter1,++iter2){
double x1=(*iter1).x-Q.x,y1=(*iter1).y-Q.y;
double x2=(*iter2).x-Q.x,y2=(*iter2).y-Q.y;
Angle+=Angle2D(x1,x2,y1,y2);
}
if(fabs(Angle-span::PI2)<=0.01) return 1;
return 0;
}
判断点是否在矩形||圆中。
矩形:只用判断
圆:只用判断圆心
查看作者更多博客:https://blog.nowcoder.net/remil