判断两线段是否相交,并求交点

2024-05-30 09:58

本文主要是介绍判断两线段是否相交,并求交点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

 

首先, 上个示意图.

根据图示, 线段a表示为端点a1和a2, 线段b表示为端点b1和b2. 为了利用向量的叉乘关系, 将线段的端点看成四个向量, 下面用粗体表示向量. 根据向量运算可知 
a=a2-a1, 
b=b2-b1. 
将线段表示为参数方程: 
a=a1 + t a 
b=b1 + u b 
其中参数t,u取值 [0,1]

两条线段相交具有如下关系: 
a1 + t a=b1 + u b 
将上式两边同时叉乘b, 得到: 
(a1+t a) x b=(b1+u b) x b 
由于b x b=0, 可得 
a1 x b + t a x b=b1 x b 
解出参数t 
t=(b1-a1)x b/(a x b) 
同理,解出参数u 
u=a x (a1-b1)/(a x b)

当0<=t<=1,且0<=u<=1时,两线段有交点. 
代入线段a的参数方程中, 即可得到线段交点坐标: 
a1+t a 
将上式中的中间变量用原始的线段端点表示, 即可得到根据线段端点表示的交点.

code 1

// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines 
// intersect the intersection point may be stored in the floats i_x and i_y.
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
    float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
    float s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    float s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
    {
        // Collision detected
        if (i_x != NULL)
            *i_x = p0_x + (t * s1_x);
        if (i_y != NULL)
            *i_y = p0_y + (t * s1_y);
        return 1;
    }

    return 0; // No collision
}
code 2

优化版本,排除线段平行情况,避免精度误差

int get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
    float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
    float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
    s10_x = p1_x - p0_x;
    s10_y = p1_y - p0_y;
    s32_x = p3_x - p2_x;
    s32_y = p3_y - p2_y;

    denom = s10_x * s32_y - s32_x * s10_y;
    if (denom == 0)//平行或共线
        return 0; // Collinear
    bool denomPositive = denom > 0;

    s02_x = p0_x - p2_x;
    s02_y = p0_y - p2_y;
    s_numer = s10_x * s02_y - s10_y * s02_x;
    if ((s_numer < 0) == denomPositive)//参数是大于等于0且小于等于1的,分子分母必须同号且分子小于等于分母
        return 0; // No collision

    t_numer = s32_x * s02_y - s32_y * s02_x;
    if ((t_numer < 0) == denomPositive)
        return 0; // No collision

    if (fabs(s_numer) > fabs(denom) || fabs(t_numer) > fabs(denom))
        return 0; // No collision
    // Collision detected
    t = t_numer / denom;
    if (i_x != NULL)
        *i_x = p0_x + (t * s10_x);
    if (i_y != NULL)
        *i_y = p0_y + (t * s10_y);

    return 1;
}

这篇关于判断两线段是否相交,并求交点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1016107

相关文章

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

JavaScript全屏,监听页面是否全屏

在JavaScript中,直接监听浏览器是否进入全屏模式并不直接支持,因为全屏API主要是关于请求和退出全屏模式的,而没有直接的监听器可以告知页面何时进入或退出全屏模式。但是,你可以通过在你的代码中跟踪全屏状态的改变来模拟这个功能。 以下是一个基本的示例,展示了如何使用全屏API来请求全屏模式,并在请求成功或失败时更新一个状态变量: javascriptlet isInFullscreen =

【Python如何输入升高和体重判断你是偏胖还是偏瘦】

1、求体质指数得Python代码如下: # BMI(Body Mass Index)指数:简称体质指数,# 是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。# 常用指标:BMI<18.5 偏瘦 18.5<=MBI<=24 正常 MBI>24 偏胖# 计算公式:BMI=体重kg/身高的平方ma = eval(input("请输入你的体重(kg):")) # 输入体重b = e

算法11—判断一个树是不是二叉查询树

问题: 给定一个二叉树,判断它是否是二叉查询树。 思路: 要判断是否是二叉查询树,标准就是看每一个节点是否满足:1、左节点及以下节点的值比它小;2、右节点及以下节点的值比它大。当然,前提是子节点都存在的情况。所以,我们需要从根节点不断向下递归,只要所有节点都满足,那么就是BST,否则,就不是。 代码: [java]  view plain copy pri

算法7— 判断一个单链表是否有环,如果有,找出环的起始位置

第一种方法是从单链表head开始,每遍历一个,就把那个node放在hashset里,走到下一个的时候,把该node放在hashset里查找,如果有相同的,就表示有环,如果走到单链表最后一个node,在hashset里都没有重复的node,就表示没有环。 这种方法需要O(n)的空间和时间。 第二种方法是设置两个指针指向单链表的head, 然后开始遍历,第一个指针走一步,第二个指针走两步,如果没

算法6— 判断两个链表是否相交

问题: 给出两个单向链表的头指针,比如h1、h2,判断链表是否相交,如果不相交返回NULL;如果相交,返回指向第一个相交节点的指针。时间复杂度控制在O(n)。 分析: 如果两单向链表相交的话,一定是Y型相交,不可能出现X型,弄清楚这点后接下来的工作就是: (1)先找到h1,h2的最后一个节点L1和L2,同时记录节点数量a,b;(这里假设 a > b) (2)判断最后一个节点是否相同

新建帐套提示“无法创建数据库!请检查目录…是否存在,以及系统空间是否充足.

1、在K/3安装路径下K3ERP文件夹下,找到DBFILE文件夹;2、右击单击“DBFILE”文件夹,选择“属性”→【安全】→【添加】,选择【高级】→【立即查找】→找到everyone用户;3、把该用户添加到【用户和组】中,并赋予“完全控制权限”。

如何判断和处理.DS_Store文件

在Mac上经常会遇到.DS_Store文件,.DS_Store是Mac OS保存文件夹的自定义属性的隐藏文件,如文件的图标位置或背景色,相当于Windows的desktop.ini.那么在使用os.listdir(path)等函数对文件进行操作的时候就会出现invalid literal for int() with base 10 错误。这是因为.DS_Store文件也会包含进去

JS奇偶数判断例子

JS奇偶数判断例子

判断字符串是否为Python标识符

import keyword,stringdef Identifier(s):#内置关键字kw = keyword.kwlist # Bifsbifs = dir(__builtins__) s_list = list(s)# 关键字判断if (s in kw) | (s in bifs):return 'keyWord'# 数字、字母、下划线以及开头判断 elif not s_list[0