问题:平面坐标系中,给定两条线段,已知这两条线段的各个端点坐标,判断这两条线段是否相交?如果相交,求出交点坐标。
首先,我们罗列出所有两条线段相交时的场景,如下图:
总共有8种场景。
我们再仔细分析这些场景,我们会发现第5、第6、第7和第8这四种场景有一个共同特点是:存在线段的端点重合,而剩余的其它四个场景是不存在线段端点重合的。
有端点重合的情况
我们先分析有端点重合的场景。
当发现一个端点存在重合时,我们再判断剩余的端点是否也是相等。
如果另一个端点也是相等的,则视为第7种场景,即两条线段是相同线段,完全重合;
如果另一个端点不相等,我们则将不相等的两个点连接成向量(下图中第5、第6、第8场景中表示A、C两点连成向量,当然连成向量也是一样的。图中我们用红色表示非重合点连接而成的新向量,用绿色表示原先的一条线段所代表的向量),如下图所示:
我们再将向量与原先的任一条线段向量作叉乘
如果叉乘结果不为0,表示新向量与作叉乘的线段不平行,那么可以推断出是第5种场景。
如果叉乘结果为0,表示新向量与作叉乘的线段平行,也就是进入第6和第8种情况。
此时我们采用点乘的方式来判断剩余两点是否在重合点的同一侧(即表示图中点A、C两点是否在重合点同一侧)。以重合点为向量尾部,即组成向量和向量(以可以叫向量,因为点B和点D重合了)进行点乘。
如果内积大于0,就是同一侧,即第8种场景,如果内积小于0,即第6种场景。
没有端点重合的情况
讨论清楚有端点重合的情况之后,我们再来讨论不存在端点重合的场景。
我们先取两条线段中的其中一条线段,视作基础的计算向量。假设取线段AB作为基础的计算向量,我们通过叉乘的手段依次来判断另一条线段上的两个端点是否与线段AB共线,如
(公式中向量也可以采用向量),
若果外积等于0,表示点C与线段AB共线;
如果外积不等于0,表示点C与线段AB不共线。
同理,(公式中向量也可以采用向量)也是一样的,可以求出点D是否与线段AB共线。
同理,我们再选另一个线段作为基础的计算向量,再执行一遍上面的流程,我们就可以知道点A和点B与线段CD的相对位置情况
结合两次的计算结果,我们就可以知道两条线段之间的相对位置情况了。
以向量作为基础计算向量时,我们可以知道点C、D相对于线段AB的位置;
以向量作为基础计算向量时,我们可以知道点A、B相对于线段CD的位置;
第1种场景的充分必要条件是:
线段AB与CD所在的直线相交,即点A和点B分别在直线CD的两边;
且,线段CD与AB所在的直线相交,即点C和点D分别在直线AB的两边;
第2种场景是只有有一个点与另一条线段共线,那我们只要再去判断一下这个共线的点的坐标范围是否在线段两个端点的坐标范围内,如果是,则交点就是这个共线点。
第3、4种场景,就是说四个点都共线,那么我们只要排序判断一下各个端点的坐标,看是第3种场景、第4种场景还是属于其它没有共同交集的场景。
至此,我们已经理清楚所有的八种场景。总的流程图如下:
计算交点坐标
除了第1种场景之外,其它七种场景都是非常容易求得交点和交集区间的。对于第1种场景,我们剩余工作主要是如何计算出这个交点坐标。
首先,我们先将两条相交的线段的各个端点作连线,并以其中一条原有线段为底线,另一条线段上的两个端点分别作垂直高线到该底线上,如上图所示,我们以线段AB作为底,h1为点C到AB的高,h2为点D到AB的高。
设,
则
即可求得交点O的坐标
至此,整体解决思路已经完成。
今天是2023年的除夕夜,祝大家在兔年中新年新气象。
后期再把代码补充上来,如果我没忘记的话。