空间直线与球面相交算法

简介: 空间直线与球面相交算法

空间直线与球面相交算法

目录

1. 原理推导

1.1. 直线公式

在严格的数学定义中,直线是无线延长,没有端点的线;射线是一端有端点,另外一段没有端点无线延长的线。但在具体的计算机几何实现中,不可能去找到这种无线延长,没有端点的线,所以这里直线的定义更加近于线段,如果线段选的够长,那么这个线段就可以认为是直线或者射线。

空间直线的数学定义是,已知直线L上一点M0(x0,y0,c0),以及直线L的方向向量s(m,n,p),那么空间直线L的方程为:

xx0m=yy0n=zz0p

以上是空间直线的标准式方程(点向式方程)。令上面式子的比值为t,那么直线的参数式方程为:

{x=x0+mty=y0+ntz=z0+pt

这两个方程是无法直接在实际情况中使用的,毕竟很多时候都是直接给出经过直线的两个点。我在《已知线段上某点与起点的距离,求该点的坐标》这篇博文中论述过:

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

P=O+tD

很明显,直线的参数式方程与上篇博文中描述的其实是一个意思,起点O就是M0(x0,y0,c0),方向向量D就是s(m,n,p)

{x=Ox+Dxty=Oy+Dytz=Oz+Dzt

并且,采取这种公式描述还有个好处,局势t的取值范围为0到1,否则就在直线的两个端点之外,也就很有可能不是你需要的点。

1.2. 求交

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

(XCx)2+(YCy)2+(ZCz)2=R2

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

(Ox+DxtCx)2+(Oy+DytCy)2+(Oz+DztCz)2=R2

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

得到t后,将其带入到(1)式中,就得到想要的交点。不过注意t的范围一般是0到1,这是与直线给的起点位置与终点位置有关的。

推到这里就会发现原来全部都是高中数学知识,应该还做过题目来着。

2. 具体实现

具体的C++实现如下:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
const double EPSILON = 0.0000000001;
// 3D vector
struct Vector3d
{
public:
  Vector3d()
  {
  }
  ~Vector3d()
  {
  }
  Vector3d(double dx, double dy, double dz)
  {
    x = dx;
    y = dy;
    z = dz;
  }
  // 矢量赋值
  void set(double dx, double dy, double dz)
  {
    x = dx;
    y = dy;
    z = dz;
  }
  // 矢量相加
  Vector3d operator + (const Vector3d& v) const
  {
    return Vector3d(x + v.x, y + v.y, z + v.z);
  }
  // 矢量相减
  Vector3d operator - (const Vector3d& v) const
  {
    return Vector3d(x - v.x, y - v.y, z - v.z);
  }
  //矢量数乘
  Vector3d Scalar(double c) const
  {
    return Vector3d(c*x, c*y, c*z);
  }
  // 矢量点积
  double Dot(const Vector3d& v) const
  {
    return x * v.x + y * v.y + z * v.z;
  }
  // 矢量叉积
  Vector3d Cross(const Vector3d& v) const
  {
    return Vector3d(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
  }
  bool operator == (const Vector3d& v) const
  {
    if (abs(x - v.x) < EPSILON && abs(y - v.y) < EPSILON && abs(z - v.z) < EPSILON)
    {
      return true;
    }
    return false;
  }
  double x, y, z;
};
//求解一元二次方程组ax*x + b*x + c = 0
void SolvingQuadratics(double a, double b, double c, vector<double>& t)
{
  double delta = b * b - 4 * a * c;
  if (delta < 0)
  {
    return;
  }
  if (abs(delta) < EPSILON)
  {
    t.push_back(-b / (2 * a));
  }
  else
  {
    t.push_back((-b + sqrt(delta)) / (2 * a));
    t.push_back((-b - sqrt(delta)) / (2 * a));
  }
}
void LineIntersectSphere(Vector3d& O, Vector3d& E, Vector3d& Center, double R, vector<Vector3d>& points)
{
  Vector3d D = E - O;     //线段方向向量
  double a = (D.x * D.x) + (D.y * D.y) + (D.z * D.z);
  double b = (2 * D.x * (O.x - Center.x) + 2 * D.y * (O.y - Center.y) + 2 * D.z* (O.z - Center.z));
  double c = ((O.x - Center.x)*(O.x - Center.x) + (O.y - Center.y) * (O.y - Center.y) + (O.z - Center.z) * (O.z - Center.z)) - R * R;
  vector<double> t;
  SolvingQuadratics(a, b, c, t);
  for (auto it : t)
  { 
    if (it >= 0 && it <= 1)
    {
      points.push_back(O + D.Scalar(it));
    }   
  }
}
int main()
{
  Vector3d O(20, 30, 40);
  Vector3d E(20, 20, 20); 
  Vector3d Center(20, 20, 20);
  double R = 15;
  vector<Vector3d> points;
  LineIntersectSphere(O, E, Center, R, points);
  cout<<"该直线(线段)与球面有"<< points.size() <<"个交点"<<endl;
  for (auto it : points)
  {
    printf("%lf\t%lf\t%lf\n", it.x, it.y, it.z);
  } 
}

最终运行的结果:

再次注意,我这里是把线段当成直线判断的,如果希望判断整个直线与球面的交点,应该略去最后的关于t是否在0到1之间的判断,此时应该会有两个交点。

3. 参考

  1. 空间直线同球体交点求解

分类: 计算几何

标签: 球面 , 直线 , 相交 , 计算几何


相关文章
|
6月前
|
存储 算法 物联网
R-Tree算法:空间索引的高效解决方案
【5月更文挑战第17天】R-Tree是用于多维空间索引的数据结构,常用于地理信息系统、数据库和计算机图形学。它通过分层矩形区域组织数据,支持快速查询。文章介绍了R-Tree的工作原理、应用场景,如地理信息存储和查询,以及Python的`rtree`库实现示例。此外,还讨论了R-Tree的优势(如空间效率和查询性能)与挑战(如实现复杂和内存消耗),以及优化和变种,如R* Tree和STR。R-Tree在机器学习、实时数据分析等领域有广泛应用,并与其他数据结构(如kd-trees和quad-trees)进行比较。未来趋势将聚焦于优化算法、动态适应性和分布式并行计算。
209 1
|
3月前
|
算法
计算空间物体包围球的两种算法实现
计算空间物体包围球的两种算法实现
48 0
|
3月前
|
算法 C++
空间中判断点在三角形内算法(方程法)
空间中判断点在三角形内算法(方程法)
58 0
|
3月前
|
算法
空间点与直线距离算法
空间点与直线距离算法
54 0
|
3月前
|
算法 Java 索引
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
36 0
|
5月前
|
算法 计算机视觉
图像处理之霍夫变换(直线检测算法)
图像处理之霍夫变换(直线检测算法)
51 0
|
5月前
|
机器学习/深度学习 算法
五种基于RGB色彩空间统计的皮肤检测算法
五种基于RGB色彩空间统计的皮肤检测算法
41 0
|
5月前
|
存储 算法
数据结构学习记录——图应用实例-六度空间(题目描述、算法思路、伪代码及解读、图解)
数据结构学习记录——图应用实例-六度空间(题目描述、算法思路、伪代码及解读、图解)
57 0
|
6月前
|
算法 数据可视化
圆填充( CIRCLE PACKING)算法圆堆图圆形空间填充算法可视化
圆填充( CIRCLE PACKING)算法圆堆图圆形空间填充算法可视化
|
26天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。