直线的参数表示,直线可以用直线上一点P0和方向向量v表示。
直线上所有点P满足P=P0+tv,其中t称为参数。如果已知直线上的
两个不同点A和B,则方向向量为B-A。所以参数方程为A+(B-A)t
参数方程设定范围即可表示线段和射线。
Point GetLineInstersection(Point P, Vector v, Point Q, Vector w)
{
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w);
return P + v*t;
}
double Distance(Point P, Point A, Point B)
{
Vector v1 = B - A, v2 = p - A;
return fabs(Cross(v1, v2) / Length(v1));//不取绝对值,得到的是有向距离
}
点到先端的距离,点到线段的距离有两种可能。
投影点为Q,如果Q在线段AB上,则所求距离就是P点到直线AB的距离。
Q在射线BA上,则所求距离为QA的距离
否则为QB的距离,判断Q的位置可以用点积进行。
double DistanceToSegment(Point P, Point A, Point B)
{
if(A == B) return Length(P -A);
vector v1 = B - A, v2 = P - A, v3 = P - B;
if(dcmp(Dot(v1, v2)) < 0) return Length(v2);
else if(dcmp(Dot(v1, v3)) > 0) return Length(v3);
else return fabs(Cross(v1, v2)) / Length(v1);
}
点在直线上的投影。把直线AB写成参数式A+tv,并且设Q的参数为t0,那么Q=A+t0*v。
根据PQ垂直于AB,两个向量的点积应该为0,因此Dot(v,P-(A+t0v))=0.
根据分配率,有Dot(v,P-A)-t0*Dot(v,v)=0,这样就可以解出t0,从而得到Q点。
Point GetLineProjection(Point P, Point A, Point B)
{
Vector v = B - A;
return A + v*(Dot(v, P-A) / Dot(v, v));
}
线段相交判定充要条件,每条线段的两个端点都在另一条线段的两侧。
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2)
{
double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4)<0;
}
如果c1,c2都是0,表示两线段共线,这时可能会有部分重叠的情况。都不是0,只有一种
判断方式,就是判断一个点shifou在一条线段上。
bool OnSegment(Point p, Point a1, Point a2)
{
return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p))<0;
}