Graphics 如何检查线段和从与水平面成一定角度的点发出的线光线之间的交点?

Graphics 如何检查线段和从与水平面成一定角度的点发出的线光线之间的交点?,graphics,geometry,Graphics,Geometry,给定一条线段,即两个点(x1,y1)和(x2,y2),一个点p(x,y)和一个角度θ。我们如何找到这条线段和从P以θ角从水平方向发出的线射线是否相交?如果它们相交,如何找到相交点?让我们标记点q=(x1,y1)和q+s=(x2,y2)。因此s=(x2− x1,y2− y1)。那么问题看起来是这样的: 设r=(cosθ,sinθ)。然后通过p的射线上的任何点都可以表示为p+tr(对于标量参数0≤ t) 线段上的任何点都可以表示为q+us(对于标量参数0≤ U≤ 1) 如果我们能找到t和u,那么

给定一条线段,即两个点(x1,y1)和(x2,y2),一个点p(x,y)和一个角度θ。我们如何找到这条线段和从P以θ角从水平方向发出的线射线是否相交?如果它们相交,如何找到相交点?

让我们标记点q=(x1,y1)和q+s=(x2,y2)。因此s=(x2− x1,y2− y1)。那么问题看起来是这样的:

r=(cosθ,sinθ)。然后通过p的射线上的任何点都可以表示为p+tr(对于标量参数0≤ t) 线段上的任何点都可以表示为q+us(对于标量参数0≤ U≤ 1)

如果我们能找到t和u,那么这两条线相交,使得pp+tr=q+us

有关如何找到该点(或确定不存在该点)的信息,请参阅


如果为0,则线段与光线相交≤ t和0≤ U≤ 1.

谢谢Gareth的精彩回答。下面是用Python实现的解决方案。可以随意删除测试,只需复制粘贴实际函数即可。我遵循了这里出现的方法的总结

将numpy导入为np
def震级(矢量):
返回np.sqrt(np.dot(np.array(vector),np.array(vector)))
def范数(向量):
返回np.数组(向量)/幅值(np.数组(向量))
def lineRayIntersectionPoint(光线原点、光线方向、点1、点2):
"""
>>>#线段
>>>z1=(0,0)
>>>z2=(10,10)
>>>
>>>#测试射线1——相交射线
>>>r=(0,5)
>>>d=标准值((1,0))
>>>len(线光线相交点(r,d,z1,z2))==1
真的
>>>#测试射线2——相交射线
>>>r=(5,0)
>>>d=范数((0,1))
>>>len(线光线相交点(r,d,z1,z2))==1
真的
>>>#测试射线3——相交垂直射线
>>>r0=(0,10)
>>>r1=(10,0)
>>>d=范数(np.数组(r1)-np.数组(r0))
>>>len(LineRay相交点(r0,d,z1,z2))==1
真的
>>>#测试射线4——相交垂直射线
>>>r0=(0,10)
>>>r1=(10,0)
>>>d=范数(np.数组(r0)-np.数组(r1))
>>>len(线光线相交点(r1,d,z1,z2))==1
真的
>>>#测试射线5——非相交反平行射线
>>>r=(-2,0)
>>>d=范数(np.数组(z1)-np.数组(z2))
>>>len(LineRay相交点(r,d,z1,z2))==0
真的
>>>#测试射线6——相交垂直射线
>>>r=(-2,0)
>>>d=范数(np.数组(z1)-np.数组(z2))
>>>len(LineRay相交点(r,d,z1,z2))==0
真的
"""
#转换为numpy数组
rayOrigin=np.array(rayOrigin,dtype=np.float)
光线方向=np.array(norm(光线方向),dtype=np.float)
point1=np.array(point1,dtype=np.float)
point2=np.array(point2,dtype=np.float)
#二维射线线段相交检验
# http://bit.ly/1CoxdrG
v1=光线原点-点1
v2=点2-点1
v3=np.array([-rayDirection[1],rayDirection[0]])
t1=np.交叉(v2,v1)/np.点(v2,v3)
t2=np.dot(v1,v3)/np.dot(v2,v3)
如果t1>=0.0,t2>=0.0,t2,这里是其他答案中给出的算法的C代码:

    /// <summary>
    /// Returns the distance from the ray origin to the intersection point or null if there is no intersection.
    /// </summary>
    public double? GetRayToLineSegmentIntersection(Point rayOrigin, Vector rayDirection, Point point1, Point point2)
    {
        var v1 = rayOrigin - point1;
        var v2 = point2 - point1;
        var v3 = new Vector(-rayDirection.Y, rayDirection.X);


        var dot = v2 * v3;
        if (Math.Abs(dot) < 0.000001)
            return null;

        var t1 = Vector.CrossProduct(v2, v1) / dot;
        var t2 = (v1 * v3) / dot;

        if (t1 >= 0.0 && (t2 >= 0.0 && t2 <= 1.0))
            return t1;

        return null;
    }
//
///返回从光线原点到交点的距离,如果没有交点,则返回null。
/// 
公共双人房?GetRayToLineSegmentIntersection(点光线原点、向量光线方向、点1、点2)
{
var v1=光线原点-点1;
var v2=点2-点1;
var v3=新向量(-raydroduction.Y,raydroduction.X);
var dot=v2*v3;
如果(数学绝对值(dot)<0.000001)
返回null;
var t1=向量叉积(v2,v1)/点;
变量t2=(v1*v3)/dot;

如果(t1>=0 & &(t2>=0 & & t2),这只是射线与线段相交测试的一部分。您没有考虑射线和线段平行的可能性。在这种情况下,点积点(v2,v3)将是0(或接近0)。.@SyaifulNizamYahya双精度值是从光线原点沿光线到交点的距离。可以通过以下方式获得交点:光线原点+光线方向*距离,给定光线方向已规范化(长度为1)。如果将摘要更改为“喜欢”,可能会更好“返回光线原点和交点之间的距离”谢谢,我终于让它工作了。请看这里@SyaifulNizamYahya我澄清了总结评论,谢谢。
    /// <summary>
    /// Returns the distance from the ray origin to the intersection point or null if there is no intersection.
    /// </summary>
    public double? GetRayToLineSegmentIntersection(Point rayOrigin, Vector rayDirection, Point point1, Point point2)
    {
        var v1 = rayOrigin - point1;
        var v2 = point2 - point1;
        var v3 = new Vector(-rayDirection.Y, rayDirection.X);


        var dot = v2 * v3;
        if (Math.Abs(dot) < 0.000001)
            return null;

        var t1 = Vector.CrossProduct(v2, v1) / dot;
        var t2 = (v1 * v3) / dot;

        if (t1 >= 0.0 && (t2 >= 0.0 && t2 <= 1.0))
            return t1;

        return null;
    }