如何计算两线段在平面中的交点

简介

大家好,我是simple,我的理想是利用科技手段来解决生活中遇到的各种问题

计算两线段在平面中的交点需要以下步骤:

  1. 确定两线段的端点坐标。
  2. 判断线段是否平行。
  3. 计算交点坐标。
  4. 判断交点是否在两线段之间。

斜截式

初始思路是这样的,既然知道了两条线段的点,那我直接根据公式列出y = kx + b。只要通过斜率判断如果斜率相同就表示为重合或者是平行,那就没有交点,如果斜率不相同,那必然有一个交点,只要解了x,y值就大功告成了。

判断是否在线上:判断解出的x和y是否分别在x1,x2与y1,y2之间即可。

浅浅证明一下: 因为:

math 复制代码
    ∵ y1 = k1 * x1 + b1
    ∵ y2 = k1 * x2 + b1
    两等式相减,得:
    y1 - y2 = k1 * (x1 - x2)
    ∴ k1 = (y1 - y2) / (x1 - x2)
    k2同理可求
js 复制代码
/**
 * 计算两条线段的交点坐标
 * @param {Array} path1 - 第一条线段顶点数组
 * @param {Array} path2 - 第二条线段顶点数组
 * @returns {Object} - 交点坐标对象
 */
getCross(path1, path2) {
    // 计算交点的坐标
    const x1 = path1[0].x;
    const y1 = path1[0].y;
    const x2 = path1[1].x;
    const y2 = path1[1].y;

    const x3 = path2[0].x;
    const y3 = path2[0].y;
    const x4 = path2[1].x;
    const y4 = path2[1].y;

    const k1 = (y1 - y2) / (x1 - x2);
    const b1 = y1 - k1 * x1;

    const k2 = (y3 - y4) / (x3 - x4);
    const b2 = y3 - k2 * x3;
    
    const x = (b2 - b1) / (k1 - k2);
    const y = k1 * x + b1;

    if (
        y >= Math.min(y1, y2) &&
        y <= Math.max(y1, y2) &&
        y >= Math.min(y3, y4) &&
        y <= Math.max(y3, y4) &&
        x >= Math.min(x1, x2) &&
        x <= Math.max(x1, x2) &&
        x >= Math.min(x3, x4) &&
        x <= Math.max(x3, x4)
    ) {
        return {
            x: x,
            y: y
        }
    }
    return null;
}

一顿操作猛如虎,战绩一看0-9。

y1是有可能等于y2的,这还不是最致命的,最致命的是x1也是有可能等于x2的。当y1 == y2的时候,在求得k1 = (y1 - y2) / (x1 - x2)的过程时k1直接变成0,而公式变成了y = b,x1 == x2的时候,分母变成0。害,换方案吧。

参数方程式

三个参数分别表示直线上的两个已知点以及参数,即:

scss 复制代码
    x = x1 + t1(x2 - x1)
    y = y1 + t1(y2 - y1)
    且符合0 <= t1 <= 1(如果t>1或者t<0,表明在该线段的延长线上,但不在该线段上,等于0的时候表明在x1上,等于1表明在x2上)

知道了上述公式,计算就简单很多了。也浅浅推导一下公式吧。

scss 复制代码
    ∵ x = x1 + t1(x2 - x1)
    ∵ x = x2 + t2(x4 - x3)
    ∴ x1 + t1(x2 - x1) = x2 + t2(x4 - x3)
    同理 y1 + t1(y2 - y1) = y2 + t2(y4 - y3)

简化后得到

<math xmlns="http://www.w3.org/1998/Math/MathML"> t 1 = x 3 ( y 4 − y 3 ) + y 1 ( x 4 − x 3 ) − y 3 ( x 4 − x 3 ) − x 1 ( y 4 − y 3 ) ( ( x 2 − x 1 ) ( y 4 − y 3 ) − ( x 4 − x 3 ) ( y 2 − y 1 ) ) t1 = \frac{x3(y4 - y3) + y1(x4 - x3) - y3(x4 - x3) - x1(y4 - y3)}{((x2 - x1)(y4 - y3) - (x4 - x3)(y2 - y1))} </math>t1=((x2−x1)(y4−y3)−(x4−x3)(y2−y1))x3(y4−y3)+y1(x4−x3)−y3(x4−x3)−x1(y4−y3)

t2暂时用不上了,这里就先不简化了。

仔细看看得到简化后的分母,(x2 - x1)(y4 - y3) - (x4 - x3)(y2 - y1);有点眼熟吗?这个叫叉积,当叉积为0的时候,表明两线段平行或者重合。我们只需要提前将分母计算一下,刚好也可以避免分母为0的情况。

js 复制代码
/**
 * 计算两条线段的交点坐标
 * @param {Array} path1 - 第一条线段顶点数组
 * @param {Array} path2 - 第二条线段顶点数组
 * @returns {Object} - 交点坐标对象
 */
getCross(path1, path2) {
    // 计算交点的坐标
    const x1 = path1[0].x;
    const y1 = path1[0].y;
    const x2 = path1[1].x;
    const y2 = path1[1].y;

    const x3 = path2[0].x;
    const y3 = path2[0].y;
    const x4 = path2[1].x;
    const y4 = path2[1].y;

    const denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
    if (denom === 0) {
        // 两条线段平行,无交点
        return null;
    }

    const t = (x3 * (y4 - y3) + y1 * (x4 - x3) - y3 * (x4 - x3) - x1 * (y4 - y3)) / denom;

    const intersectionX = x1 + t * (x2 - x1);
    const intersectionY = y1 + t * (y2 - y1);

    // 判断交点是否在两条线段之间
    if (t < 1 && t > 0) {
        return {
            x: intersectionX,
            y: intersectionY
        }
    } else {
        return null;
    }
}

总结

至此大功告成,使用参数式方程可以解决所有的线段交点的问题,但是使用斜截式方程会对平行于y轴的线段无效。

相关推荐
毕小宝20 分钟前
逻辑回归(下): Sigmoid 函数的发展历史
算法·机器学习·逻辑回归
f89790707024 分钟前
layui动态表格出现 横竖间隔线
前端·javascript·layui
小叮当爱咖啡26 分钟前
DenseNet算法:口腔癌识别
算法
希望有朝一日能如愿以偿29 分钟前
算法(食物链)
算法
鱼跃鹰飞30 分钟前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试
summ1ts41 分钟前
组合数求法汇总
c++·数学·算法·离散数学·组合数学
二十雨辰1 小时前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
@qike2 小时前
【C++】—— 日期类的实现
c语言·c++·笔记·算法·学习方法
霸王蟹2 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
luthane2 小时前
python 实现djb2哈希算法
python·算法·哈希算法