判断线段和圆是否相交
判断圆和线段相交,分两种情况:
1. 如图A所示,当圆心与线段的距离大于圆的半径时,线段与圆肯定不相交
2. 如图B,C所示,两个端点都不在圆内,那么看圆心到线段所在直线的垂足是否小于半径且垂足是否在线段上;我们可以利用余弦定理,避免判断垂足是否在线段上,只要圆心到两端点的得角度都为锐角,那么他们必然相交。
推导过程:
- 线段所在直线方程的一般公式为:ax+by+c=0;线段两端点A(x1,y1)B(x2,y2),圆心O(x0,y0).
此处补充直线方程的五种形式:
一般式为ax+by+c=0,它的优点就是它可以表示平面上的任意一条直线,仅此而已.
斜截式y=kx+b,就不能表示垂直x轴的直线x=a.
点斜式y-y0=k(x-x0),也不能表示垂直x轴的直线x=a
两点式(y-y1)/(y2-y1)=(x-x1)/(x2-x1).不能表示两点x1=x2或y1=y2时的直线(即垂直或水平直线)
截距式x/a+y/b=1不能表示截距为0时的直线,比如正比例直线.
- 所以根据两点式,可以求得a=y2-y1,b=x1-x2,c=x1y2-x2y1;
- 在根据点到直线的距离公式:
再补充一下余弦定理:
这样的话,根据余弦定理的向量求法,CosA=(x0-x1)(x2-x1)+(y0-y1)(y2-y1) (省略了分母部分,因为分母是正数)
#include <iostream>
using namespace std;
typedef struct
{
int x,int y;
}point;
point A,B,C,O;
int pan_duan(point *p1,point *p2,double r)
{
double a,b,c,dist1,dist2,angle1,angle2;//ax+by+c=0;
if(p1->x==p2->x)
a=1,b=0,c=-p1->x;//特殊情况判断,分母不能为零
else if(p1->y==p2->y)
a=0,b=1,c=-p1->y;//特殊情况判断,分母不能为零
else
{
a=p1->y-p2->y;
b=p2->x-p1->x;
c=p1->x*p2->y-p1->y*p2->x;
}
dist1=a*O.x+b*O.y+c;
dist1*=dist1;
dist2=(a*a+b*b)*r*r;
if(dist1>dist2)return 0;//点到直线距离大于半径
angle1=(O.x-p1->x)*(p2->x-p1->x)+(O.y-p1->y)*(p2->y-p1->y);
angle2=(O.x-p2->x)*(p1->x-p2->x)+(O.y-p2->y)*(p1->y-p2->y);
if(angle1>0&&angle2>0)return 1;
return 0;
}