1. 概述

在本教程中,我们将讨论如何检测一个与一条直线或线段之间的碰撞。

我们将从问题定义开始,通过示例帮助理解。接着会介绍两种解决思路:

  • 一种是判断直线与圆的碰撞
  • 另一种是判断线段与圆的碰撞

两种方法的数学原理相似,但实现细节略有不同。

2. 问题定义

我们有一个圆 C,圆心为 O,半径为 R。同时,有一条由两点 P 和 Q 确定的直线 L。

目标是判断圆 C 和直线 L 是否存在交点。

举个例子更直观:

1 1536x880

  • 图 A:直线 L 与圆 C 没有交点,结果为 ❌ false
  • 图 B:直线 L 与圆 C 有两个交点,结果为 ✅ true

3. 直线与圆的碰撞检测

3.1 数学原理

判断直线与圆是否相交的核心思想是:

计算圆心 O 到直线 L 的最短距离,如果这个距离小于等于圆的半径 R,说明直线与圆相交或相切。

这个最短距离其实就是圆心 O 到直线 L 的投影长度。

我们可以通过三角形面积法来求这个距离:

  • 用三点 O、P、Q 构造一个三角形
  • 利用叉积计算三角形面积
  • 再根据面积公式反推高(即最短距离)

公式如下: $$ \text{distance} = \frac{2 \times \text{TriangleArea}(O, P, Q)}{\text{distance}(P, Q)} $$

3.2 三角形面积计算

我们用叉积来计算三角形面积:

double triangleArea(Point A, Point B, Point C) {
    double ax = B.x - A.x;
    double ay = B.y - A.y;
    double bx = C.x - A.x;
    double by = C.y - A.y;
    double cross = ax * by - ay * bx;
    return Math.abs(cross) / 2.0;
}

3.3 算法实现

boolean lineCircleCollision(double radius, Point O, Point P, Point Q) {
    double minDist = 2 * triangleArea(O, P, Q) / distance(P, Q);
    return minDist <= radius;
}

3.4 时间复杂度

✅ 时间复杂度为 O(1),因为只涉及常数次运算。

4. 线段与圆的碰撞检测

4.1 数学原理

线段与圆的碰撞检测比直线复杂,因为线段是有限的。我们需要考虑以下情况:

  • 圆心 O 到线段 PQ 的最短距离是否小于等于 R
  • 同时,线段是否完全在圆内或部分在圆内

关键点

  • 如果 O 的投影在 PQ 上,则使用三角形面积法求最短距离
  • 如果不在 PQ 上,则取 O 到端点 P 或 Q 的最小距离

同时,我们还要判断线段的最远端点是否在圆外,否则线段可能完全在圆内,不算碰撞。

4.2 算法实现

boolean lineSegmentCircleCollision(double radius, Point O, Point P, Point Q) {
    double maxDist = Math.max(distance(O, P), distance(O, Q));
    double minDist;

    // 判断投影是否在线段上
    if (dot(P.subtract(O), P.subtract(Q)) > 0 && dot(Q.subtract(O), Q.subtract(P)) > 0) {
        minDist = 2 * triangleArea(O, P, Q) / distance(P, Q);
    } else {
        minDist = Math.min(distance(O, P), distance(O, Q));
    }

    return minDist <= radius && maxDist >= radius;
}

⚠️ 注意:dot() 是向量点乘函数,subtract() 是向量减法函数,需要自行实现。

4.3 时间复杂度

✅ 时间复杂度仍为 O(1),所有运算都是固定次数。

5. 总结

我们介绍了两种碰撞检测算法:

类型 原理简述 时间复杂度
直线 & 圆 计算圆心到直线最短距离 O(1)
线段 & 圆 先判断投影是否在线段上,再分别计算最短/最远距离 O(1)

两种方法都基于几何原理,适用于游戏开发、图形学、物理引擎等场景。

优点:高效、准确、实现简单
限制:仅适用于 2D 平面场景,不适用于三维空间

如果你在实现过程中遇到投影判断逻辑不清晰、点乘叉积理解困难等问题,欢迎留言交流,我们一起踩坑填坑 😄


原始标题:Circle Line-Segment Collision Detection Algorithm

« 上一篇: Minimax 算法详解
» 下一篇: 事务简介