如何判断两条给定线段是否相交?

给定由一个三维向量 INLINECODE6c2bf068 表示的两条线段,其中每条线段 INLINECODE58dc80a0 由存储在 INLINECODEd0ec92a6 和 INLINECODE2b137472 中的端点定义(每个端点包含 2 个整数),我们的任务是确定这两条线段是否彼此相交。

示例:

> 输入:points[][][] = [ [[1, 1], [10, 1]] , [[1, 2], [10, 2]] ]

> 输出:No

> 解释:给定的线段彼此平行。

> !1

> 输入:points[][][] = [ [[10, 0], [0, 10]] , [[0, 0], [10, 10]] ]

> 输出:Yes

> 解释:给定的线段互为镜像并在中点相交。

> !2

我们要利用下面的方向概念来解决这个问题。

三个有序点的方向

> 平面上有序三元组点的方向可以是:

>

> – 逆时针

> – 顺时针

> – 共线

>

> 下图展示了 三种不同的可能方向:

>

> !image

>

> 如果 的方向是共线,那么 的方向也是共线。

> 如果 的方向是顺时针,那么 的方向就是逆时针,反之亦然。

利用线的方向 – O(1) 时间和 O(1) 空间

> 我们的核心思路是利用线的方向来确定它们是否相交。当且仅当满足以下两个条件之一时,两条线段 [p1, q1] 和 [p2, q2] 相交:

>

> 1. 一般情况:

>

> – [p1, q1, p2] 和 [p1, q1, q2] 拥有不同的方向。

> – [p2, q2, p1] 和 [p2, q2, q1] 拥有不同的方向。

>

> 下图包含了一般情况的示例:

> !image

>

> 2. 特殊情况:

>

> – [p1, q1, p2]、[p1, q1, q2]、[p2, q2, p1] 和 [p2, q2, q1] 全部共线

> – [p1, q1] 和 [p2, q2] 的 x 轴投影相交。

> – [p1, q1] 和 [p2, q2] 的 y 轴投影相交。

>

> 下图包含特殊情况下的示例:

> !image

方法:

> 我们的思路是首先找到分析一般情况和特殊情况所需的四个方向。我们要讨论了一种在文章“3个有序点的方向”中寻找 3 个有序点方向的方法。此后,检查一般情况,如果两个条件都为真,则返回 true,否则检查特殊情况。现在,对于特殊情况,点必须是共线的,并且点应该在线段上。要检查点是否位于线段上,请检查该点是否位于 x 和 y 坐标的最大值和最小值之间。

C++

`

#include 
using namespace std;

// 检查点 q 是否位于线段 ‘pr‘ 上的函数
bool onSegment(vector& p, vector& q, vector& r) {
    return (q[0] = min(p[0], r[0]) &&
            q[1] = min(p[1], r[1]));
}

// 查找有序三元组 的方向的函数
// 0 --> p, q 和 r 共线
// 1 --> 顺时针
// 2 --> 逆时针
int orientation(vector& p, vector& q, vector& r) {
    int val = (q[1] - p[1]) * (r[0] - q[0]) -
              (q[0] - p[0]) * (r[1] - q[1]);

    // 共线
    if (val == 0) return 0;

    // 顺时针或逆时针
    // 1 代表顺时针,2 代表逆时针
    return (val > 0) ? 1 : 2;
}

// 检查两条线段是否相交的函数
bool doIntersect(vector<vector<vector>>& points) {

    // 找到分析一般情况和特殊情况所需的四个方向
    int o1 = orientation(points[0][0], points[0][1], points[1][0]);
    int o2 = orientation(points[0][0], points[0][1], points[1][1]);
    int o3 = orientation(points[1][0], points[1][1], points[0][0]);
    int o4 = orientation(points[1][0], points[1][1], points[0][1]);

    // 一般情况
    if (o1 != o2 && o3 != o4)
        return true;

    // 特殊情况
    // p1, q1 和 p2 共线且 p2 位于线段 p1q1 上
    if (o1 == 0 && 
    onSegment(points[0][0], points[1][0], points[0][1])) return true;

    // p1, q1 和 q2 共线且 q2 位于线段 p1q1 上
    if (o2 == 0 && 
    onSegment(points[0][0], points[1][1], points[0][1])) return true;

    // p2, q2 和 p1 共线且 p1 位于线段 p2q2 上
    if (o3 == 0 && 
    onSegment(points[1][0], points[0][0], points[1][1])) return true;

    // p2, q2 和 q1 共线且 q1 位于线段 p2q2 上
    if (o4 == 0 && 
    onSegment(points[1][0], points[0][1], points[1][1])) return true;

    return false; 
}

// 主函数用于测试
int main() {
    // 示例 1
    vector<vector<vector>> points1 = {{{1, 1}, {10, 1}}, {{1, 2}, {10, 2}}};
    if (doIntersect(points1)) {
        cout << "Yes
";
    } else {
        cout << "No
";
    }

    // 示例 2
    vector<vector<vector>> points2 = {{{10, 0}, {0, 10}}, {{0, 0}, {10, 10}}};
    if (doIntersect(points2)) {
        cout << "Yes
";
    } else {
        cout << "No
";
    }

    return 0;
}
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/36077.html
点赞
0.00 平均评分 (0% 分数) - 0