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

简介

大家好,我是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轴的线段无效。

相关推荐
旭久17 分钟前
vue-计算两个日期之前的天数小方法
前端·javascript·vue.js
游王子21 分钟前
Vue.js组件(6):echarts组件
前端·vue.js·echarts
Solitudefire35 分钟前
蓝桥杯刷题——day9
算法·蓝桥杯
Smile_Gently1 小时前
Ubuntu环境 nginx.conf详解(二)
运维·服务器·前端·nginx·ubuntu
三万棵雪松1 小时前
1.系统学习-线性回归
算法·机器学习·回归·线性回归·监督学习
m0_748233881 小时前
黑马程序员JavaWeb开发教程(前端部分) ---笔记分享
前端·笔记
温轻舟1 小时前
前端开发 -- 自定义鼠标指针样式
开发语言·前端·javascript·css·html·温轻舟
Easy数模2 小时前
基于LR/GNB/SVM/KNN/DT算法的鸢尾花分类和K-Means算法的聚类分析
算法·机器学习·支持向量机·分类·聚类
天天打码2 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
2401_858286112 小时前
117.【C语言】数据结构之排序(选择排序)
c语言·开发语言·数据结构·笔记·算法·排序算法