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

简介

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

相关推荐
Bug.ink几秒前
BUUCTF——WEB(4)
前端·网络安全·靶场·ctf·buuctf
L Jiawen1 分钟前
【Web】RESTful风格
前端·后端·restful
爱编码的傅同学6 分钟前
【单例模式】深入理解懒汉与饿汉模式
java·javascript·单例模式
momo(激进版)7 分钟前
前端打包时自动更新版本号
前端
胖虎112 分钟前
UIKit实现一个渐变文字的UILabel(核心思想及实现过程)
前端·mask·渐变文字·ios渐变文字·渐变label
用户68026590511914 分钟前
2026年企业级网络监控选型指南
javascript·后端·面试
alphardex20 分钟前
一个普通魔法师的 2025 年度总结
前端·年终总结
surtr127 分钟前
常见排序模板(冒泡排序,希尔排序,堆排序,归并排序,快速排序)
数据结构·算法·贪心算法·排序算法
德莱厄斯32 分钟前
AI 纪元 3 年,2025 论前端程序员自救
前端·ai编程·vibecoding
WX-bisheyuange42 分钟前
基于Spring Boot的社团管理系统的设计与实现
前端·javascript·vue.js·毕业设计