空间直线与球面的相交算法

文章目录

  • 1. 原理推导
    • 1.1. 直线公式
    • 1.2. 求交
  • 2、代码实现:
    • 2.1 关键代码:
    • 2.2 main()函数的调用

1. 原理推导

1.1. 直线公式

空间直线的数学定义是,已知直线L上一点M0(x0,y0,c0),以及直线L的方向向量s(m,n,p),那么空间直线L的方程为:
在这里插入图片描述
以上是空间直线的标准式方程(点向式方程)。令上面式子的比值为t,那么直线的参数式方程为:
空间直线与球面的相交算法_第1张图片

对于知道线段的起点O和终点E,显然方向向量为D=E−O。这时,根据射线的向量方程,线段上某一点P为

P=O+tD
转化为参数方程就是:

在这里插入图片描述

并且,采取这种公式描述还有个好处,参数t的取值范围为0到1,否则就在直线的两个端点之外。

1.2. 求交

根据数学定义,已知球心坐标C(Cx,Cy,Cz)与球的半径R,球面的公式为:

在这里插入图片描述

联立(1)(2)两式,最终会得到一个关于t的一元二次方程:

在这里插入图片描述

一元二次方程组的有无解,单个解,以及双解三种可能,这也符合空间直线与球面相交的直观认识,要么相切有一个交点,要么相交有两个交点,否则的话可能没有交点。

得到t后,将其带入到(1)式中,就得到想要的交点。并且,由参数t 就可以判断交点的位置。

2、代码实现:

2.1 关键代码:

/* 两个向量的差, (vector1 - vector2). */
vec3d vdiff(const vec3d vector1, const vec3d vector2)
{
    vec3d v;
    v.x = vector1.x - vector2.x;
    v.y = vector1.y - vector2.y;
    v.z = vector1.z - vector2.z;
    return v;
}

/* 两个向量的和, (vector1 + vector2). */
vec3d vsum(const vec3d vector1, const vec3d vector2)
{
    vec3d v;
    v.x = vector1.x + vector2.x;
    v.y = vector1.y + vector2.y;
    v.z = vector1.z + vector2.z;
    return v;
}

/* 向量的数乘1. */
vec3d vmul(const vec3d vector, const double n)
{
    vec3d v;
    v.x = vector.x * n;
    v.y = vector.y * n;
    v.z = vector.z * n;
    return v;
}

/* 向量的数乘2. */
vec3d vdiv(const vec3d vector, const double n)
{
    vec3d v;
    v.x = vector.x / n;
    v.y = vector.y / n;
    v.z = vector.z / n;
    return v;
}

/* 向量的欧几里得范数 */
double vdist(const vec3d v1, const vec3d v2)
{
    double xd = v1.x - v2.x;
    double yd = v1.y - v2.y;
    double zd = v1.z - v2.z;
    return sqrt(xd * xd + yd * yd + zd * zd);
}

/* 向量的欧几里得范数  */
double vnorm(const vec3d vector)
{
    return sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
}

/* 两个向量的点积*/
double dot(const vec3d vector1, const vec3d vector2)
{
    return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z;
}

/*两个向量的叉积 */
vec3d cross(const vec3d vector1, const vec3d vector2)
{
    vec3d v;
    v.x = vector1.y * vector2.z - vector1.z * vector2.y;
    v.y = vector1.z * vector2.x - vector1.x * vector2.z;
    v.z = vector1.x * vector2.y - vector1.y * vector2.x;
    return v;
}


/* Intersecting a sphere sc with radius of r, with a line p1-p2.
 * Return zero if successful, negative error otherwise.
 * mu1 & mu2 are constant to find points of intersection.
 * 球和直线的相交
 *
*/
int sphereline(const vec3d p1, const vec3d p2, const vec3d sc, double r, double *const mu1, double *const mu2)
{
   double a,b,c;
   double bb4ac;
   vec3d dp;

   dp.x = p2.x - p1.x;
   dp.y = p2.y - p1.y;
   dp.z = p2.z - p1.z;

   a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;

   b = 2 * (dp.x * (p1.x - sc.x) + dp.y * (p1.y - sc.y) + dp.z * (p1.z - sc.z));

   c = sc.x * sc.x + sc.y * sc.y + sc.z * sc.z;
   c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
   c -= 2 * (sc.x * p1.x + sc.y * p1.y + sc.z * p1.z);
   c -= r * r;

   bb4ac = b * b - 4 * a * c;

   if (fabs(a) == 0 || bb4ac < 0) {
      *mu1 = 0;
      *mu2 = 0;
      return -1;
   }

   *mu1 = (-b + sqrt(bb4ac)) / (2 * a);
   *mu2 = (-b - sqrt(bb4ac)) / (2 * a);

   return 0;
}



2.2 main()函数的调用

  int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    vec3d O;
    O.x = 30;
    O.y = 40;
    O.z = 70;

    vec3d E;
    E.x = 30;
    E.y = -40;
    E.z = 70;

    vec3d Center;
    Center.x = 0;
    Center.y = 0;
    Center.z = 70;


    double R = 50;
    double res1,res2;

    int  result = 1;
    result = sphereline(O,E,Center,R,&res1,&res2);

    qDebug()<<"求解得到的参数t为:";
    qDebug()<<"t1:"<< QString::number(res1,'g',5);
    qDebug()<<"t2:" <<QString::number(res2,'g',5);

    vec3d ex,t2,t3;
    double h;

    ex = vdiff(E, O); // vector result1-result2
    h = vnorm(ex); // scalar result1-result2
    ex = vdiv(ex, h); // unit vector ex with respect to result1 (new coordinate system)
    /* t2 points to the intersection */
    t2 = vmul(ex, res1*h);
    t2 = vsum(O, t2);

    t3 = vmul(ex, res2*h);
    t3 = vsum(O, t3);

    qDebug()<<"求解得到如下的交点:";
    qDebug()<< QString::number(t2.x,'g',5);
    qDebug()<< QString::number(t2.y,'g',5);
    qDebug()<< QString::number(t2.z,'g',5)<<endl;

    qDebug()<< QString::number(t3.x,'g',5);
    qDebug()<< QString::number(t3.y,'g',5);
    qDebug()<< QString::number(t3.z,'g',5)<<endl;


    return a.exec();
}

调试输出:
空间直线与球面的相交算法_第2张图片

你可能感兴趣的:(数学与算法,算法,空间直线,球面,相交)