用Qt/C++计算直线与圆柱体、圆台、长方体的交点

一、空间直线与圆柱体表面交点

//x1 y1 z1 柱内的点,x2 y2 z2 柱外的点,a,b是圆柱底面圆心的x,y坐标,l,h是圆柱下底和上底的z值
//此方法返回值为圆柱内的点到交点的距离
float path_cylinder_vertical(float x1, float y1, float z1, float x2, float y2, float z2, float a, float b, float l, float h,float r)
{
    /*侧面出射:从z方向上看,视为x-y的二维平面,出射点在圆周
     * 先求二维直线方程y=kx+b,圆周方程(x-a)^2+(y-b)^2=r^2 (a,b为底面圆心的x,y坐标,r为半径)
     * 两者结合求出交点x,y值,带入空间直线求出z值
     * 判断z值是否在圆柱范围内[l,h],在则为侧面出射,否则
     * 底面出射:z=l或h代入空间直线,求出x,y值,判断是否在底面圆周内,若是则为底面出射
     */
    float ix1,ix2,ix;
    float iy1,iy2,iy;
    float iz;
    if(x2==x1 && y2==y1)
        return z2-z1;
    if(y2==y1){
        ix1 = sqrt(r*r-pow(y2-b,2))+a;
        ix2 = -sqrt(r*r-pow(y2-b,2))+a;
        if(abs(x2-ix1)<abs(x2-x1))
            ix = ix1;
        else
            ix = ix2;
        iy = y1;
        iz = (ix*z1-x2*z1-ix*z2+x1*z2)/(x1-x2);
    }
    else if(x2==x1){
        iy1 = sqrt(r*r-pow(x1-a,2))+b;
        iy2 = -sqrt(r*r-pow(x1-a,2))+b;
        if(abs(y2-iy1)<abs(y2-y1))
            iy = iy1;
        else
            iy = iy2;
        ix = x1;
        iz = (iy*z1-y2*z1-iy*z2+y1*z2)/(y1-y2);
    }
    else{
        float lk = (y2-y1)/(x2-x1);
        float lb = y1-lk*x1;
        float ia = lk*lk+1;
        float ib = 2*lk*(lb-b)-2*a;
        float ic = a*a+pow(lb-b,2)-pow(r,2);
        float delta = pow(ib,2)-4*ia*ic;
        if(delta<0)
            return 0;
        ix1 = (-ib+sqrt(delta))/(2*ia);
        ix2 = (-ib-sqrt(delta))/(2*ia);
        //此处我为了求两点间的交点,所以只选择了两点间的ix值,若要获取所有交点则ix1和ix2都要计算
        if(abs(x2-ix1)<abs(x2-x1))
            ix = ix1;
        else
            ix = ix2;
        iy = ix*lk+b;
        iz = (ix*z1-x2*z1-ix*z2+x1*z2)/(x1-x2);
    }
    if(iz>=l && iz<=h){
        float path = sqrt(pow(ix-x1,2)+pow(iy-y1,2)+pow(iz-z1,2));
        qDebug()<<ix<<iy<<iz;
        return path;
    }
    else{
        if(iz>h){
            iz = h;
            ix = (iz*x1-z2*x1-iz*x2+z1*x2)/(z1-z2);
            iy = (iz*y1-z2*y1-iz*y2+z1*y2)/(z1-z2);
            if((pow(ix-a,2)+pow(iy-b,2))<=pow(r,2)){
                float path = sqrt(pow(ix-x1,2)+pow(iy-y1,2)+pow(iz-z1,2));
                qDebug()<<ix<<iy<<iz;
                return path;
            }
            else
                return 0;
        }
        else{
        //ix,iy,iz为两点间直线与圆柱交点坐标
            iz = l;
            ix = (iz*x1-z2*x1-iz*x2+z1*x2)/(z1-z2);
            iy = (iz*y1-z2*y1-iz*y2+z1*y2)/(z1-z2);
            if((pow(ix-a,2)+pow(iy-b,2))<=pow(r,2)){
                float path = sqrt(pow(ix-x1,2)+pow(iy-y1,2)+pow(iz-z1,2));
                qDebug()<<ix<<iy<<iz;
                return path;
            }
            else
                return 0;
        }
    }
}

二、空间直线与圆台交点坐标

此例的圆台底面圆心为(0,0,0)

//x1y1z1圆台内的点,x2y2z2圆台外的点,h圆台高,r1 r2上下底半径
float GlobalFormula::path_cone(float x1, float y1, float z1, float x2, float y2, float z2,float h,float r1,float r2)
{
    /*从x轴方向看,求出圆锥曲面z与y的关系:y=(z-b)/k
     * 圆锥曲面方程为x^2+y^2=((z-b)/k)^2
     * 带入直线参数方程:
     * x=x1+t(x2-x1)
     * y=y1+t(y2-y1)
     * z=z1+t(z2-z1)
     * 求出交点z值,然后带入直线求出xy值
     */
    float lk = h/(r1-r2);
    float lb = -lk*(r2/2);

    float a = x2-x1;
    float b = y2-y1;
    float c = z2-z1;
    if(c==0)
        return 0;

    float A = (pow(a,2)+pow(b,2))/pow(c,2)-1.0/pow(lk,2);
    float B = (2*x1*a+2*y1*b)/c+2*lb/pow(lk,2)-(2*z1*(a*a+b*b))/pow(c,2);
    float C = x1*x1+y1*y1-(2*z1*(x1*a+y1*b))/c+z1*z1*(a*a+b*b)/pow(c,2)-lb*lb/pow(lk,2);
    float delta = B*B-4*A*C;
    if(delta<0)
        return 0;
    float iz1 = (-B+sqrt(delta))/(2*A);
    float iz2 = (-B-sqrt(delta))/(2*A);
    float iz;
    if(iz1<iz2)
        iz = iz1;
    else
        iz = iz2;
    if(iz>m_cone.T2 && iz<m_cone.D1+m_cone.T2){
        //侧面出射
        float ix = (iz*x1-z2*x1-iz*x2+z1*x2)/(z1-z2);
        float iy = (iz*y1-z2*y1-iz*y2+z1*y2)/(z1-z2);
        qDebug()<<ix<<iy<<iz;
        float path = sqrt(pow(ix-x1,2)+pow(iy-y1,2)+pow(iz-z1,2));
        return path;
    }
    else if(iz<m_cone.T2){
        //底面出射
        iz = m_cone.T2;
        float ix = (iz*x1-z2*x1-iz*x2+z1*x2)/(z1-z2);
        float iy = (iz*y1-z2*y1-iz*y2+z1*y2)/(z1-z2);
        float path = sqrt(pow(ix-x1,2)+pow(iy-y1,2)+pow(iz-z1,2));
        return path;
    }
    else
        return 0;
}

三、空间直线与长方体表面交点

此例中长方体置于x-y面上方,z轴与长方体中心同轴

float path_cuboid(float x1, float y1, float z1, float x2, float y2, float z2,float L,float W,float H)
{
    float w = W/2;
    float l = L/2;
    float h = H;

    float x,y,z;
    //前面
    x = (w*x1-x1*y2-w*x2+y1*x2)/(y1-y2);
    z = (w*z1-z1*y2-w*z2+y1*z2)/(y1-y2);
    if(x>=-l && x<=l && z>=0 && z<=h)
        return sqrt(pow(x-x1,2)+pow(w-y1,2)+pow(z-z1,2));
    //后面
    x = (-w*x1-x1*y2+w*x2+y1*x2)/(y1-y2);
    z = (-w*z1-z1*y2+w*z2+y1*z2)/(y1-y2);
    if(x>=-l && x<=l && z>=0 && z<=h)
        return sqrt(pow(x-x1,2)+pow(-w-y1,2)+pow(z-z1,2));
    //左面
    y = (l*y1-x2*y1-l*y2+x1*y2)/(x1-x2);
    z = (l*z1-x2*z1-l*z2+x1*z2)/(x1-x2);
    if(y>=-w && y<=w && z>=0 && z<=h)
        return sqrt(pow(l-x1,2)+pow(y-y1,2)+pow(z-z1,2));
    //右面
    y = (-l*y1-x2*y1+l*y2+x1*y2)/(x1-x2);
    z = (-l*z1-x2*z1+l*z2+x1*z2)/(x1-x2);
    if(y>=-w && y<=w && z>=0 && z<=h)
        return sqrt(pow(-l-x1,2)+pow(y-y1,2)+pow(z-z1,2));
    //上面
    x = (h*x1-z2*x1-h*x2+z1*x2)/(z1-z2);
    y = (h*y1-z2*y1-h*y2+z1*y2)/(z1-z2);
    if(x>=-l && x<=l && y>=-w && y<=w)
        return sqrt(pow(x-x1,2)+pow(y-y1,2)+pow(h-z1,2));
    //下面
    if(x2>=-l && x2<=l && y2>=-w && y2<=w && z2==0)
        return sqrt(pow(x2-x1,2)+pow(y2-y1,2)+pow(z2-z1,2));
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值