C++ 中射线与平面的交集
在本文中,首先,我们将获得有关 C++ 中光线平面相交的完整指导。
首先,我们将讨论矢量运算及其实现。 接下来,我们将讨论射线平面相交的概念及其在 C++ 中的实现。
在 C++ 中使用向量运算
在这里,我们将介绍相关的矢量运算及其在 C++ 中的实现。 我们需要以下功能:
- 减号运算符:计算两点之间的距离。
- 点积:计算两个向量之间点积的函数,其结果为实数。
- 乘法运算符:计算两个向量的叉积。
- 带浮点参数的乘法运算符:计算向量和标量值之间的标量乘法。
- 幅度函数:计算向量的幅度。
- 归一化函数:计算向量的法线。
- 最后,流运算符被重载以显示向量。
这是完整的矢量 3D 类。 main 函数检查/演示 vector 3D 类的成员函数。
#include <iostream>
#include <math.h>
using namespace std;
class Vec3{
float x;
float y;
float z;
public:
Vec3(){ x, y, z = 0;}
Vec3(float x, float y, float z){
this->x = x;
this->y = y;
this->z = z;
}
Vec3& operator += (const Vec3 &b){
x = x + b.x;
y = y + b.y;
z = z + b.z;
return *this;
}
Vec3& operator-=(const Vec3 &b){
x = x - b.x;
y = y - b.y;
z = z - b.z;
return *this;
}
Vec3 operator + (const Vec3 &b){
Vec3 newV = *this;
newV += b;
return newV;
}
Vec3 operator - (const Vec3 &b){
Vec3 newV = *this;
newV -= b;
return newV;
}
Vec3 operator * (const Vec3 &b){ //cross operator
Vec3 newV;
newV.x = y * b.z - z * b.y;
newV.y = x * b.z - z * b.x;
newV.z = x * b.y - y * b.x;
return newV;
}
Vec3& operator *= (const float s){ //Dot equal operator
x = x * s;
y = y * s;
z = z * s;
return *this;
}
Vec3 operator * (const float s){ //Dot equal operator
Vec3 newV = *this;
return newV *= s;
}
float mag(){ return sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2)); }
Vec3& normalize(){
double mag = this->mag();
x /= mag;
y /= mag;
z /= mag;
return *this;
}
//Dot operator
float dot(const Vec3 &b){ return x*b.x + y*b.y + z*b.z; }
friend ostream& operator << (ostream &out, const Vec3 &v){
out << "(" << v.x << ", " << v.y << ", " << v.z << ")\n";
return out;
}
};
int main(){
Vec3 v1(-5, 7, 2);
Vec3 v2(4, 12, 1);
Vec3 v3(1, 1, 1);
cout << "Vec1 = " << v1 << endl;
v1+=v2;
cout << "Result of adding Vec2 in Vec1 = " << v1 << endl;
v1-=v3;
cout << "Result of subtracting Vec3 from vec1 = " << v1 << endl;
v1*=5;//dot operation
cout << "Resultant after the scaling of Vec1 with a value of 5 = " << v1 << endl;
cout << "Magnitude for Vec1 = " << v1.mag() << endl;
v1.normalize();
cout << "Vec1 after normalization = " << v1 << endl;
cout << "Dot product of Vec1 and Vec2 = " << v1*v2 << endl;
return 0;
}
这是主函数的输出,显示了矢量 3D 类的准确实现。
Vec1 = (-5, 7, 2)
Result of adding Vec2 in Vec1 = (-1, 19, 3)
Result of subtracting Vec3 from vec1 = (-2, 18, 2)
Resultant after the scaling of Vec1 with a value of 5 = (-10, 90, 10)
Magnitude for Vec1 = 91.1043
Vec1 after normalization = (-0.109764, 0.987878, 0.109764)
Dot product of Vec1 and Vec2 = (-0.329293, -0.548821, -5.26868)
C++ 中射线与平面的交集
从这里开始,我们假设读者对矢量运算的概念相当熟悉。 我们进一步假设读者对平面有基本的了解。
如果您对这些概念感到不自在,请点击此链接了解有关矢量运算和平面的更多信息。
让我们看看一些正式的数学事实和细节,以找到平面中的光线交点。
我们知道两个正交或垂直向量的点积总是0。假设a和b是两个垂直或正交向量,则a.b=0。
现在,考虑平面上的点 p0,表示平面与原点和垂直于平面的矢量 n 的距离。 我们可以通过从点 p0 减去平面上的任意点来计算向量 p。
合成矢量位于平面内并垂直于平面法线。
这个事实给了我们等式:
(p-p0) . N = 0 (i)
将 l0 和 l 分别视为射线的起点和射线的方向。 我们可以使用参数形式到达平面(意味着相交于点 p):
l0 + l * t = p (ii)
如果射线不平行于平面,则沿射线方向 t 次; 光线会使飞机感兴趣。 接下来,我们可以将等式(ii)中的p值代入等式(i),我们得到:
(l0 + l * t – p0) . n = 0
我们想要计算 t,这可以帮助我们使用参数方程计算交点的位置。 让我们来解方程:
l * t . n + (l0 – p0) . n = 0
l * t . n = - (l0 – p0) . n
t = - (l0 – p0) . n / l . n
我们需要确定分母中的线和平面法线的点积,因为如果值为 0 或接近 0,结果将是无穷大,这意味着光线和平面是平行的。 因此,我们将检查分母并返回 false,这意味着没有解决方案(即交点)。
下面的函数可以检查射线是否与平面相交:
bool intersection plane (Vec3 &n, Vec3 &p0, Vec3 & lo, Vec3 &l, float &t){
//assuming vectors are all normalized
float denom = n.dot(l);
if (denom < 0.00005 && denom >-0.00005) /denom is near to 0
return false;
Vec3 p010 = p0 – l0;
t = p010.dot(n);
if t>=0) return true;
return false;
}
使用 if
条件,我们检查分母是否接近 0,这意味着会有无限结果。 如果光线平行于平面,则平面法线与光线方向的点积为 0; 因此,我们返回 false。
否则,我们将计算 t 并返回 true,这意味着射线与平面相交。 我们可以使用 t 找到一个交点。
接下来,我们在下面有完整的代码来找到射线和平面的交点。
#include <iostream>
#include <math.h>
using namespace std;
class Vec3{
float x;
float y;
float z;
public:
Vec3(){ x, y, z = 0;}
Vec3(float x, float y, float z){
this->x = x;
this->y = y;
this->z = z;
}
Vec3& operator += (const Vec3 &b){
x = x + b.x;
y = y + b.y;
z = z + b.z;
return *this;
}
Vec3& operator += (const float s){
x = x + s;
y = y + s;
z = z + s;
return *this;
}
Vec3 operator + (const float s){
Vec3 newV = *this;
return newV += s;
}
Vec3& operator-=(const Vec3 &b){
x = x - b.x;
y = y - b.y;
z = z - b.z;
return *this;
}
Vec3 operator + (const Vec3 &b){
Vec3 newV = *this;
newV += b;
return newV;
}
Vec3 operator - (const Vec3 &b){
Vec3 newV = *this;
newV -= b;
return newV;
}
Vec3 operator * (const Vec3 &b){ //cross operator
Vec3 newV;
newV.x = y * b.z - z * b.y;
newV.y = x * b.z - z * b.x;
newV.z = x * b.y - y * b.x;
return newV;
}
Vec3& operator * (const float s){ //Dot equal operator
x = x * s;
y = y * s;
z = z * s;
return *this;
}
float mag(){ return sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2)); }
Vec3& normalize(){
double mag = this->mag();
x /= mag;
y /= mag;
z /= mag;
}
//Dot operator
float dot(const Vec3 &b){ return x*b.x + y*b.y + z*b.z; }
friend ostream& operator << (ostream &out, const Vec3 &v){
out << "(" << v.x << ", " << v.y << ", " << v.z << ")\n";
return out;
}
};
bool intersectPlane(Vec3 &n, Vec3 &p0, Vec3 &l0, Vec3 &l, float &t) {
// considering vectors are normalized
float denom = n.dot(l); //dot product n.l
if (denom > 1e-6) {
Vec3 p0l0 = p0 - l0;
t = n.dot(p0l0) / denom;
return (t >= 0);
}
return false;
}
int main(){
Vec3 n1(3, -9, 1);//Normal
Vec3 p01(-4, 2, 2);
Vec3 l01(1, 1, 1);
Vec3 l1(1, 2, 1);
float t;
n1.normalize();
p01.normalize();
l01.normalize();
l1.normalize();
if (intersectPlane(n1, p01, l01, l1, t))
cout << "T:" << t << '\n';
else
cout << "Ray is not intersecting the plane\n";
cout << "------------------------\n";
Vec3 n2(2, 2, -2);//Normal
Vec3 p02(2, 4, 1);
Vec3 l02(1, 1, 1);
Vec3 l2(1, 2, 1);
n2.normalize();
p02.normalize();
l02.normalize();
l2.normalize();
if (intersectPlane(n2, p02, l02, l2, t))
cout << "T:" << t << '\n';
else
cout << "Ray is not intersecting the plane\n";
Vec3 intersectionPoint = l02 + l2 * t;
cout << intersectionPoint;
return 0;
}
此代码的输出是:
Ray is not intersecting the plane
------------------------
T:0.629199
(0.83422, 1.09109, 0.83422)
如您所见,在我们的第一个数据点中,射线平行于平面。 因此,分母为0。
但是,在第二组数据点中,分母大于0,所以我们可以找到交点。
相关文章
在 C++ 中通过掷骰子生成随机值
发布时间:2023/04/09 浏览次数:169 分类:C++
-
本文解释了如何使用时间因子方法和模拟 C++ 中的掷骰子的任意数方法生成随机数。了解它是如何工作的以及它包含哪些缺点。提供了一个 C++ 程序来演示伪数生成器。
在 C++ 中使用模板的链表
发布时间:2023/04/09 浏览次数:158 分类:C++
-
本文解释了使用模板在 C++ 中创建链表所涉及的各个步骤。工作程序演示了一个链表,该链表使用模板来避免在创建新变量时声明数据类型的需要。
在 C++ 中添加定时延迟
发布时间:2023/04/09 浏览次数:142 分类:C++
-
本教程将为你提供有关在 C++ 程序中添加定时延迟的简要指南。这可以使用 C++ 库为我们提供的一些函数以多种方式完成。
在 C++ 中创建查找表
发布时间:2023/04/09 浏览次数:155 分类:C++
-
本文重点介绍如何创建查找表及其在不同场景中的用途。提供了三个代码示例以使理解更容易,并附有代码片段以详细了解代码。
如何在 C++ 中把字符串转换为小写
发布时间:2023/04/09 浏览次数:63 分类:C++
-
介绍了如何将 C++ std::string 转换为小写的方法。当我们在考虑 C++ 中的字符串转换方法时,首先要问自己的是我的输入字符串有什么样的编码
如何在 C++ 中确定一个字符串是否是数字
发布时间:2023/04/09 浏览次数:163 分类:C++
-
本文介绍了如何检查给定的 C++ 字符串是否是数字。在我们深入研究之前,需要注意的是,以下方法只与单字节字符串和十进制整数兼容。
如何在 c++ 中查找字符串中的子字符串
发布时间:2023/04/09 浏览次数:65 分类:C++
-
本文介绍了在 C++ 中检查一个字符串是否包含子字符串的多种方法。使用 find 方法在 C++ 中查找字符串中的子字符串
如何在 C++ 中把字符串转换为 Char 数组
发布时间:2023/04/09 浏览次数:107 分类:C++
-
本文介绍了在 C++ 中把字符串转换为 char 数组的多种方法。使用 std::basic_string::c_str 方法将字符串转换为 char 数组