说明TPoint和TLineSeg的定义了:)
struct TPoint {
float x,y;
};
//TPoint是指线段端点的坐标
struct TLineSeg {
TPoint a,b;
};
//TLineSeg是指线段的两个端点
//这里编者巧妙地把线段和坐标两个事物通过定义一对嵌套的数据结构来简化。许多初学者会定义诸如dot1x,dot1y,dot2x,dot2y这种难以区分的数据结构。
算法简单说明:
①判断以两条线段为对角线的矩形是否相交,如果不相交两条线段肯定也不相交。
②如果相交的话,利用矢量叉乘判断两条线段是否相互跨越,如果相互跨越显然就相交,反之则不相交。
算法不难,但是一些特殊情况需要考虑到,比如两条相段共线且在断点处相交。
/******************************************************** * *
* 返回(P1-P0)*(P2-P0)的叉积。 *
* 若结果为正,则 <P0,P1> 在 <P0,P2> 的顺时针方向;(夹角为正) *
* 若为0则 <P0,P1> <P0,P2> 共线;(夹角为0) *
* 若为负则 <P0,P1> 在 <P0,P2> 的在逆时针方向; (夹角为负)*
* 可以根据这个函数确定两条线段在交点处的转向, *
* 比如确定<p0,p1>和<p1,p2>在p1处是左转还是右转,只要 *
* 求(p2-p0)×(p1-p0),若小于0则左转,大于0则右转,等于0则 *
* 共线 *
* *
\********************************************************/
float multiply(TPoint p1,TPoint p2,TPoint p0)
{
return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
//a(x1,y1),b(x2,y2)
//x1*y2-x2*y1
//确定两条线段是否相交
int intersect(TLineSeg u,TLineSeg v)
{
return( (max(u.a.x,u.b.x)> =min(v.a.x,v.b.x))&& //u中最右的点是否在v最左的点的右边
(max(v.a.x,v.b.x)> =min(u.a.x,u.b.x))&& //v中最右的点是否在u最左的点的右边
//判断这两条线段在水平层面上是否可能相交
(max(u.a.y,u.b.y)> =min(v.a.y,v.b.y))&& //u中最上的点是否在v最下的点的上边
(max(v.a.y,v.b.y)> =min(u.a.y,u.b.y))&& //v中最上的点是否在u最下的点的上边
//判断这两条线段在垂直层面上是否可能相交
(multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)> =0)&&
//判断v.a,v.b是否分布在u.b两侧(或线上)
(multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)> =0));
//判断u.a,u.b是否分布在v.a两侧(或线上)
}
几点思考:
一、对于两线段在同一直线上且头尾一点相交,最后两个判断能过这种情况。如果头尾不想交,前面四个判断不能过。
二、对于两线段平行的情况,最后两个判断不能过。
三、对于端点在另一线段中间的情况,最后两个判断能过。
四、综上,这个简单精练的判断函数值得大家进行进一步的思考与探究。
附图一张:
见附件
--