圆和射线相交 矩形和射线相交判断 lua

时间:2020-05-21
本文章向大家介绍圆和射线相交 矩形和射线相交判断 lua,主要包括圆和射线相交 矩形和射线相交判断 lua使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
global_NULL = ""
--判断射线和圆是否相交,相交的话返回交点
-- rayBeginVec3射线起点 rayNormalVec3归一化的射线方向 centerVec3圆心 r圆半径
-- return 0 表示不相交
--return 1, nearPos(近点)
function global_ray2Circle(rayBeginVec3, rayNormalVec3, centerVec3, r)
    local center2ray = Vector3.New(rayBeginVec3.x - centerVec3.x, rayBeginVec3.y - centerVec3.y, 0)
    local dotV = Vector3.Dot(center2ray, rayNormalVec3)
    local subLen = Vector3.Dot(center2ray, center2ray) - r ^ 2
    if subLen > 0 and dotV > 0 then
        -- 射线源在圆外,方向相反,不会相交
        return 0, global_NULL
    end
    local discr = dotV * dotV - subLen
    if discr < 0 then
        return 0, global_NULL
    end
    local t = -dotV - discr ^ 0.5
    t = math.max(0, t)
    return 1, Vector3.New(rayBeginVec3.x + rayNormalVec3.x * t, rayBeginVec3.y + rayNormalVec3.y * t, 0)
end

-- 两条直线的交点
function global_line2line(k1, b1, k2, b2)
    if k1 == global_NULL and k2 == global_NULL then
        return global_NULL
    end
    if k1 == global_NULL then
        return {["x"] = -b1, ["y"] =(-b1 * k2 + b2)}
    end
    if k2 == global_NULL then
        return {["x"] = -b2, ["y"] =(-b2 * k1 + b1)}
    end
    if math.abs(k1 - k2) < 0.00001 then
        --平行
        return global_NULL
    end
    local x = (b2 - b1) / (k1 - k2)
    return {["x"] = x, ["y"] =(x * k1 + b1)}
end

--获取一条直线的k和b系数
function global_lineFactor(vec3, pos)
    if vec3.x == 0 then --垂直的直线 k无效
        return global_NULL, -pos.x
    else
        local k = vec3.y / vec3.x
        return  k, pos.y - k*pos.x
    end
end

-- 射线和线段的交点
function global_rayPosLine(rayBeginVec3, rayNormalVec3, lineBegin, lineEnd)
    local lineVec3 = Vector3.New(lineEnd.x - lineBegin.x, lineEnd.y - lineBegin.y, 0)
    local k1, b1 = global_lineFactor(rayNormalVec3, rayBeginVec3)
    local k2, b2 = global_lineFactor(lineVec3, lineBegin)
    local pos = global_line2line(k1, b1, k2, b2)
    if pos ~= global_NULL then
        --判断交点在线段内、在射线内
        if ((pos.x - lineBegin.x) * (pos.x - lineEnd.x) <= 0 and (pos.y - lineBegin.y) * (pos.y - lineEnd.y) <= 0)
                and (rayNormalVec3.x * (pos.x - rayBeginVec3.x) + rayNormalVec3.y * (pos.y - rayBeginVec3.y)) >= 0
        then
            --print(stringMessage(pos))
            return pos
        end
    end
    --print("无交点")
    return global_NULL
end

--获取射线和矩形的交点(射线在矩形内,必相交)
--return pos
function global_ray2RectInner(rayBeginVec3, rayNormalVec3, LB_X, LB_Y, RT_X, RT_Y)

    local posFunc = function(a, b, c, d)
        local rightV = Vector3.New(a - rayBeginVec3.x, b - rayBeginVec3.y, 0)
        local leftV = Vector3.New(c - rayBeginVec3.x, d - rayBeginVec3.y, 0)
        local angleA = Vector3.Angle(rightV, rayNormalVec3)
        local angleB = Vector3.Angle(leftV, rayNormalVec3)
        local angleAll = Vector3.Angle(rightV, leftV)
        if angleAll >= angleA and angleAll >= angleB then
            return global_rayPosLine(rayBeginVec3, rayNormalVec3, Vector3.New(a, b, 0), Vector3.New(c, d, 0))
        end
        return global_NULL
    end
    --  右上 左上
    local pos = posFunc(RT_X,RT_Y,LB_X,RT_Y)
    if pos ~=global_NULL then
        return pos
    end
    -- 左上 左下
    local pos = posFunc(LB_X,RT_Y,LB_X,LB_Y)
    if pos ~=global_NULL then
        return pos
    end
    -- 左下 右下
    local pos = posFunc(LB_X,LB_Y,RT_X,LB_Y)
    if pos ~=global_NULL then
        return pos
    end
    -- 右下 右上
    local pos = posFunc(RT_X,LB_Y,RT_X,RT_Y)
    if pos ~=global_NULL then
        return pos
    end
    print("global_ray2RectInner 有错误! 内部射线和矩形没有交点")
    return global_NULL
end


-- 射线和矩形的交点,射线源在矩形内,矩形和x轴平行
function global_ray2RectInnerPos(rayBeginVec3, rayNormalVec3, LB_X, LB_Y, RT_X, RT_Y)
    local k = global_NULL
    if math.abs(rayNormalVec3.x) >= 0.00001 then
        k = rayNormalVec3.y / rayNormalVec3.x
        if math.abs(k) < 0.00001 then
            if rayNormalVec3.x > 0 then
                return { x = RT_X, y = rayBeginVec3.y }
            else
                return { x = LB_X, y = rayBeginVec3.y }
            end
        end
    else
        if rayNormalVec3.y > 0 then
            return { x = rayBeginVec3.x, y = RT_Y }
        else
            return { x = rayBeginVec3.x, y = LB_Y }
        end
    end
    -- 右上 左上
    local rtVec3 = Vector3.New(RT_X - rayBeginVec3.x, RT_Y - rayBeginVec3.y, 0)
    local ltVec3 = Vector3.New(LB_X - rayBeginVec3.x, RT_Y - rayBeginVec3.y, 0)
    local cossRT = Vector3.Cross(rtVec3, rayNormalVec3)
    local cossLT = Vector3.Cross(rayNormalVec3, ltVec3)
    if Vector3.Dot(cossRT, cossLT) <= 0 then
        return { x = (rayBeginVec3.x + RT_Y / k), y = RT_Y }
    end
    -- 左上 左下
    rtVec3 = Vector3.New(LB_X - rayBeginVec3.x, RT_Y - rayBeginVec3.y, 0)
    ltVec3 = Vector3.New(LB_X - rayBeginVec3.x, LB_Y - rayBeginVec3.y, 0)
    cossRT = Vector3.Cross(rtVec3, rayNormalVec3)
    cossLT = Vector3.Cross(rayNormalVec3, ltVec3)
    if Vector3.Dot(cossRT, cossLT) <= 0 then
        return { x = (rayBeginVec3.x + RT_Y / k), y = RT_Y }
    end
    -- 左下 右下
    rtVec3 = Vector3.New(LB_X - rayBeginVec3.x, LB_Y - rayBeginVec3.y, 0)
    ltVec3 = Vector3.New(RT_X - rayBeginVec3.x, LB_Y - rayBeginVec3.y, 0)
    cossRT = Vector3.Cross(rtVec3, rayNormalVec3)
    cossLT = Vector3.Cross(rayNormalVec3, ltVec3)
    if Vector3.Dot(cossRT, cossLT) <= 0 then
        return { x = (rayBeginVec3.x + RT_Y / k), y = RT_Y }
    end
    -- 右下 右上
    rtVec3 = Vector3.New(RT_X - rayBeginVec3.x, LB_Y - rayBeginVec3.y, 0)
    ltVec3 = Vector3.New(RT_X - rayBeginVec3.x, LB_Y - rayBeginVec3.y, 0)
    cossRT = Vector3.Cross(rtVec3, rayNormalVec3)
    cossLT = Vector3.Cross(rayNormalVec3, ltVec3)
    if Vector3.Dot(cossRT, cossLT) <= 0 then
        return { x = (rayBeginVec3.x + RT_Y / k), y = RT_Y }
    end
    print("global_ray2RectInnerPos 出错 没有找到交点!")
    return global_NULL
end

原文地址:https://www.cnblogs.com/sun-shadow/p/12928516.html