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

简介

大家好,我是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)

简化后得到

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))} 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轴的线段无效。

相关推荐
FPGA信号处理5 分钟前
【 凸优化】第六讲:求解器与支持向量机
算法·机器学习·支持向量机
专注仿真7 分钟前
支持向量机(SVM)算法详解与代码实例
算法·机器学习·支持向量机
Pniubi11 分钟前
力扣42接雨水(动态规划法)
算法·leetcode·职场和发展
IT_陈寒15 分钟前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
步行cgn22 分钟前
为什么既要 web.xml 又要 springmvc.xml?能不能只配一个?
xml·前端·hive
CQU_JIAKE26 分钟前
10.31[A]
算法·深度优先
风骏时光牛马29 分钟前
大模型综合能力评测:多维度性能与对齐效果对比
前端
zwc321043205530 分钟前
Day 5:threshold与inRange阈值分割
c++·图像处理·人工智能·opencv·算法·计算机视觉
云-缩影33 分钟前
实际项目中怎么选排序算法:从面试题到工程落地
java·算法·排序算法
winfredzhang35 分钟前
从零手写一个毛玻璃风格的页面搭建台:单文件 HTML 实现组件放置、面板磁吸与图层管理
前端·html