线形对象与平面相交

2023-10-30 09:50
文章标签 对象 相交 平面 线形

本文主要是介绍线形对象与平面相交,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

三维空间中的线形对象包括直线、射线和线段,为了统一三者的表达,在三维图形学中一般使用一个点和方向向量的方式来描述这些线形对象。

假设有一个点P位于线形对象上,方向向量是 d⃗  ,那么这个线形对象可以使用下面的公式来表达:

L(t)=P+td⃗ 

基于这个表达式,直线方程可以描述为:

L(t)=P+td⃗ (t)

射线方程可以描述为(P是射线的端点):

R(t)=P+td⃗ (0t)

在描述线段时,使用一对点{ P0 P1 },则线段方程是:

S(t)=P0+t(P1P0)(0t1)

平面的描述方式很多,最简单的是使用一般式 ax+by+cz+d=0 ,向量 n⃗ =[a,b,c] 是平面的法向量。

1. 直线与平面相交

PlaneLineIntersection

如上图所示,直线方程L是 P+td⃗  , 平面方程是 ax+by+cz+d=0 ,假设二者有交点(交于点Q),那么直线上的Q点也一定满足平面方程,也就是:

Q=P+td⃗  满足 ax+by+cz+D=0 (为区别直线的方向向量,平面方程的常数项写成D),将Q点带入平面方程中,得到:

a(Px+tdx)+b(Py+tdy)+c(Pz+tdz)+D=0

t=(D+aPx+bPy+cPz)adx+bdy+cdz

写成向量的形式是:

t=(D+n⃗ P)n⃗ d⃗ 

针对这个表达式展开讨论:

  1. 如果 n⃗ d⃗ =0 那么说明直线平行于平面或者直线位于平面之内。怎么判断直线是否位于平面之内呢?很简单,判断直线的另一个点P是否位于平面内即可,也就是把P点带入平面方程中,如果满足平面方程,那么直线位于平面内,不满足则二者平行。
  2. 如果 n⃗ d⃗ 0 ,那么直线和平面有唯一的交点,将t值带入到 Q=P+td⃗  可以求出二者的交点坐标。

总结如下:

  1. n⃗ d⃗ =0 aPx+bPy+cPz+D=0 直线位于平面内
  2. n⃗ d⃗ =0 aPx+bPy+cPz+D0 直线与平面平行
  3. n⃗ d⃗ 0 直线与平面有唯一交点

在编码过程中由于浮点数的舍入误差,一般将结果与一个阈值 ϵ 进行比较,通过比较快速判断直线与平面是否相交。

2. 射线与平面相交

射线的方程表达式与直线类似,但是射线稍有不同的是它表达式中的 P一定是射线的端点,如果P是射线的端点,那么计算的过程与直线中的结论完全一样,只不过需要在判断相交的时候t的取值,如果取值范围 t0 ,那么就可以带入到射线方程中求出交点Q,否则(也就是 t<0 )二者没有交点。

总结如下:

  1. n⃗ d⃗ =0 aPx+bPy+cPz+D=0 直线位于平面内
  2. n⃗ d⃗ =0 aPx+bPy+cPz+D0 直线与平面平行
  3. n⃗ d⃗ 0 t0 射线与平面有唯一交点
  4. n⃗ d⃗ 0 t<0 射线与平面没有交点

3. 线段与平面相交

线段的计算过程同样与射线类似,可以通过直线方程

S(t)=P0+t(P1P0)(0t1)

来计算,需要注意的是线段的方向向量 d⃗  ,必须是 P1P0 ,这样t的取值范围就是在[0,1]区间,如果t的取值范围不是[0,1],那么线段与平面无交点。

总结如下:

  1. 直线方程的方向向量必须是 P1P0 (直线和射线只要方向相同即可,甚至可以单位化方向向量,但是线段必须是 P1P0
  2. n⃗ d⃗ =0 aPx+bPy+cPz+D=0 直线位于平面
  3. n⃗ d⃗ =0 aPx+bPy+cPz+D0 直线与平面平行
  4. n⃗ d⃗ 0 t[0,1] 射线与平面有唯一交点
  5. n⃗ d⃗ 0 t[0,1] 射线与平面没有交点

4. 算法实现

使用OpenSceneGraph实现线段和平面的相交判断的代码如下:


/* 
*  线段和平面的相交关系判断:返回值是0表示没有交点,返回值是1表示二者有唯一交点,返回值是2表示线段位于平面内
*
*/int intersectSegmentPlane(const osg::Plane& plane, const osg::LineSegment& lineSegment, osg::Vec3d& intersection)
{double epsilon = 1e-6;osg::Vec3d planeNorm = plane.getNormal();osg::Vec3d segmentDirection = lineSegment.end() - lineSegment.start();double dotPlaneNormSegDir = planeNorm * segmentDirection;osg::Vec4d planeParam = plane.asVec4();double lineInPlane = planeParam.x() * lineSegment.start().x() + planeParam.y() * lineSegment.start().y() +planeParam.z() * planeParam.z() + planeParam.w();if (fabs(dotPlaneNormSegDir) < epsilon){//如果直线端点满足平面方程,那么直线在平面内if (fabs(lineInPlane) < epsilon){return 2;}else{return 0;}}double planeNormDotP = -(planeParam.w() + planeNorm * lineSegment.start());double t = planeNormDotP / dotPlaneNormSegDir;if (t < 0 || t > 1)return 0;intersection = lineSegment.start() + segmentDirection*t;return 1;
}

5. 参考文献

  1. Line and Segment Intersections
  2. [书籍:Geometric Tools for Computer Graphics]

这篇关于线形对象与平面相交的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/307096

相关文章

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

Java第二阶段---09类和对象---第三节 构造方法

第三节 构造方法 1.概念 构造方法是一种特殊的方法,主要用于创建对象以及完成对象的属性初始化操作。构造方法不能被对象调用。 2.语法 //[]中内容可有可无 访问修饰符 类名([参数列表]){ } 3.示例 public class Car {     //车特征(属性)     public String name;//车名   可以直接拿来用 说明它有初始值     pu

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

PHP7扩展开发之对象方式使用lib库

前言 上一篇文章,我们使用的是函数方式调用lib库。这篇文章我们将使用对象的方式调用lib库。调用代码如下: <?php $hello = new hello(); $result = $hello->get(); var_dump($result); ?> 我们将在扩展中实现hello类。hello类中将依赖lib库。 代码 基础代码 这个扩展,我们将在say扩展上增加相关代码。sa

hibernate修改数据库已有的对象【简化操作】

陈科肇 直接上代码: /*** 更新新的数据并并未修改旧的数据* @param oldEntity 数据库存在的实体* @param newEntity 更改后的实体* @throws IllegalAccessException * @throws IllegalArgumentException */public void updateNew(T oldEntity,T newEntity

类和对象的定义和调用演示(C++)

我习惯把类的定义放在头文件中 Student.h #define _CRT_SECURE_NO_WARNINGS#include <string>using namespace std;class student{public:char m_name[25];int m_age;int m_score;char* get_name(){return m_name;}int set_name

react笔记 8-19 事件对象、获取dom元素、双向绑定

1、事件对象event 通过事件的event对象获取它的dom元素 run=(event)=>{event.target.style="background:yellowgreen" //event的父级为他本身event.target.getAttribute("aid") //这样便获取到了它的自定义属性aid}render() {return (<div><h2>{

求空间直线与平面的交点

若直线不与平面平行,将存在交点。如下图所示,已知直线L过点m(m1,m2,m3),且方向向量为VL(v1,v2,v3),平面P过点n(n1,n2,n3),且法线方向向量为VP(vp1,vp2,vp3),求得直线与平面的交点O的坐标(x,y,z): 将直线方程写成参数方程形式,即有: x = m1+ v1 * t y = m2+ v2 * t

高斯平面直角坐标讲解,以及地理坐标转换高斯平面直角坐标

高斯平面直角坐标系(Gauss-Krüger 坐标系)是基于 高斯-克吕格投影 的一种常见的平面坐标系统,主要用于地理信息系统 (GIS)、测绘和工程等领域。该坐标系将地球表面的经纬度(地理坐标)通过一种投影方式转换为平面直角坐标,以便在二维平面中进行距离、面积和角度的计算。 一 投影原理 高斯平面直角坐标系使用的是 高斯-克吕格投影(Gauss-Krüger Projection),这是 横