0%

04 - 三维射线类

1. 射线

1.1 定义

  • 数学定义:
    射线 是直线的“一半”,有一个起点并向一个方向无限延伸。
  • 计算几何中的定义:
    射线 是一个有向线段。

射线有起点和终点。
一个射线定义了一个 位置 ,一个 有限长度 和一个 方向 。(除非射线长度为零)
任何射线都定义了包含这个射线的一条直线和线段。

1.2 两点表示法

使用两个端点,起点 PorgP_{org} 和终点 PendP_{end}
screenShot.png

1.3 射线的参数形式

{x(t)=x0+tΔxy(t)=y0+tΔyz(t)=z0+tΔz\begin{cases} x(t) = x_0 + t\Delta x \\ y(t) = y_0 + t\Delta y \\ z(t) = z_0 + t\Delta z \end{cases}

使用向量表示:

p(t)=p0+td\vec{p}(t) = \vec{p_0} + t \vec{d}

其中单位向量 d\vec{d} 表示射线方向,设射线的长度为 ll ,参数 t[0,l]t \in [0,l],那么射线的终点则为:

p(l)=p0+ld\vec{p}(l) = \vec{p_0} + l \vec{d}

screenShot.png

1.4 2D直线表示法

该表示法仅适用于二维空间

  • 直线公式:

{ax+by=dpn=dis\begin{cases} ax + by = d \\ \vec{p} \cdot \vec{n} = dis \end{cases}

  • 令指向点 PiP_i 的向量为 pi\vec{p_i} ,向量 pi\vec{p_i} 在沿着方向 n\vec{n} 的投影的长度为 disdis ,该直线 LL 即为所有满足该表达式的点 PiP_i 的集合;
  • 过原点 OO 向直线 LL 做一条垂线,可知该垂线过点 M(a,b)M(a,b)

NOTE:图中点 M(a,b)M(a,b) 在直线 LL 上,即有 OM=dis=a2+b2\left \Vert {\overrightarrow{OM}} \right \Vert = dis = \sqrt {a^2 + b^2} ,但是一般情况下点 M(a,b)M(a,b) 不一定在直线 LL 上。

screenShot.png

n\vec{n} 是垂直于直线的单位向量,disdis 给出了原点到直线的 有符号距离 ,这个距离是在垂直于直线的方向(平行于 n\vec{n})上度量的

  • 有符号距离:如果直线与标准向量 n\vec{n} 代表的点在原点的同一侧,则 disdis 为正;当 disdis 增大时,直线会沿着方向 n\vec{n} 平移

1.4.1 点到直线的距离

p(x0,y0)p(x_0,y_0) 到直线 LL 的距离为:

dis(p,L)=ax0+by0da2+b2dis(p,L) = \cfrac{\vert {ax_0 + by_0 - d} \vert}{\sqrt {a^2 + b^2}}

1.4.2 不同表示方法的转换

{ax+by=dpn=dis\begin{cases} ax + by = d \\ \vec{p} \cdot \vec{n} = dis \end{cases}

其中有以下关系:

{n=(a,b)a2+b2=(aa2+b2,ba2+b2)dis=da2+b2\begin{cases} \vec{n} = \cfrac{(a,b)}{\sqrt {a^2 + b^2}} = (\cfrac{a}{\sqrt {a^2 + b^2}},\cfrac{b}{\sqrt {a^2 + b^2}}) \\[2ex] dis = \cfrac{d}{\sqrt {a^2 + b^2}} \end{cases}

同时,

{a=b=d=\begin{cases} a = \\[2ex] b = \\[2ex] d = \end{cases}

2. 示例代码

2.1 成员变量

1
2
3
4
5
6
7
8
9
10
11
// 起点向量
Vector3 start;

// 使用一个单位向量表示射线的方向
Vector3 dir;

// 射线的长度
float len;

// 射线参数,从 0 到 1
float t;

2.2 构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 构造函数
Ray3::Ray3()
{
st = Vector3(0, 0, 0);
dir = Vector3(0, 0, 0);
len = 0;
t = 1;
}

Ray3::Ray3(const Vector3& inSt, const Vector3& inDir)
{
st = Vector3(inSt.x, inSt.y, inSt.z);
dir = Vector3(inDir.x, inDir.y, inDir.z);
dir.normalize();
len = vectorMag(dir);
t = 1;
}

Ray3::Ray3(const Vector3& inSt, const Vector3& inDir, float inLen)
{
st = Vector3(inSt.x, inSt.y, inSt.z);
dir = Vector3(inDir.x, inDir.y, inDir.z);
dir.normalize();
this->len = inLen;
t = 1;
}