求解直线与平面的交点

36 篇文章 32 订阅

求解直线与平面的交点

微信公众号:幼儿园的学霸

目录

前言

直线与平面的交点求解相关的内容在网上已经有很多资料进行介绍,目前所看到的博文在数学模型建立上都是正确的,但是其编程实现却存在问题,导致只有部分情况下能够正确求出直线与平面的交点,另外一些情况下求出的交点却是错误的.本文对原理进行推导并实现正确的编码.

数学模型推导

已知经过两点 P 1 ( x 1 , y 1 , z 1 ) , P 2 ( x 2 , y 2 , z 2 ) P_1(x_1,y_1,z_1),P_2(x_2,y_2,z_2) P1(x1,y1,z1),P2(x2,y2,z2)的直线与平面 a x + b y + c z + d = 0 ax+by+cz+d=0 ax+by+cz+d=0相交于点P,求点P的坐标.
该问题几何模型如下:
几何模型

求解该问题的一种方法是建立方程组,联立求解点的坐标.该方法在数学实现上非常直观,但是求方程组的解稍微麻烦.

另一种是通过向量法进行求解.推导过程如下:
设 m = P 1 P → P 1 P 2 → , 则 O P → = O P 1 → + P 1 P → = O P 1 → + m ∗ P 1 P 2 → 设 m = \frac{\overrightarrow {P_1P}}{\overrightarrow{P_1P_2}},则 \\ \overrightarrow {OP} = \overrightarrow {OP_1} + \overrightarrow {P_1P} =\overrightarrow {OP_1} + m*\overrightarrow {P_1P_2} m=P1P2 P1P ,OP =OP1 +P1P =OP1 +mP1P2
其中:
m = P 1 P → P 1 P 2 → = P 1 D → P 1 D 2 → = ∣ P 1 D → ∣ ∣ P 1 D 2 → ∣ m = \frac{\overrightarrow {P_1P}}{\overrightarrow{P_1P_2}} = \frac{\overrightarrow {P_1D}}{\overrightarrow{P_1D_2}} = \frac{\lvert \overrightarrow {P_1D}\rvert } {\lvert \overrightarrow{P_1D_2} \rvert} m=P1P2 P1P =P1D2 P1D =P1D2 P1D

∣ P 1 D → ∣ \lvert \overrightarrow {P_1D}\rvert P1D 为点P1到平面的距离,计算公式如下:
∣ P 1 D → ∣ = ∣ a x 1 + b y 1 + c z 1 + d ∣ a 2 + b 2 + c 2 \lvert \overrightarrow {P_1D}\rvert = \frac{\lvert {ax_1+by_1+cz_1+d} \rvert} {\sqrt{a^2+b^2+c^2}} P1D =a2+b2+c2 ax1+by1+cz1+d
另外:
∣ P 1 D 2 → ∣ = ∣ P 1 P 2 → ∣ c o s θ = ∣ P 1 P 2 → ∣ ∗ ∣ P 1 P 2 → ⋅ P 1 D 2 → ∣ ∣ P 1 P 2 → ∣ ∣ P 1 D 2 → ∣ = ∣ P 1 P 2 → ⋅ P 1 D 2 → ∣ P 1 D 2 → ∣ ∣ {\lvert \overrightarrow{P_1D_2} \rvert} = {\lvert \overrightarrow{P_1P_2} \rvert}cos{\theta} = {\lvert \overrightarrow{P_1P_2} \rvert} * \frac{\lvert{\overrightarrow{P_1P_2} \cdot \overrightarrow{P_1D_2} } \rvert} {\lvert{\overrightarrow{P_1P_2}} \rvert \lvert{\overrightarrow{P_1D_2}} \rvert} \\ =\lvert{ \overrightarrow{P_1P_2} \cdot \frac{\overrightarrow{P_1D_2}}{\lvert{\overrightarrow{P_1D_2}} \rvert} } \rvert P1D2 =P1P2 cosθ=P1P2 P1P2 P1D2 P1P2 P1D2 =P1P2 P1D2 P1D2

显然, P 1 D 2 → ∣ P 1 D 2 → ∣ \frac{\overrightarrow{P_1D_2}}{\lvert{\overrightarrow{P_1D_2}} \rvert} P1D2 P1D2 表示平面的单位法向量,其用坐标的形式表示如下:
P 1 D 2 → ∣ P 1 D 2 → ∣ = ( a , b , c ) a 2 + b 2 + c 2 \frac{\overrightarrow{P_1D_2}}{\lvert{\overrightarrow{P_1D_2}} \rvert} = \frac{(a,b,c)}{\sqrt{a^2+b^2+c^2}} P1D2 P1D2 =a2+b2+c2 (a,b,c)
因此:
∣ P 1 D 2 → ∣ = ∣ P 1 P 2 → ⋅ P 1 D 2 → ∣ P 1 D 2 → ∣ ∣ = P 1 D 2 → ∣ P 1 D 2 → ∣ = ∣ a ( x 2 − x 1 ) + b ( y 2 − y 1 ) + c ( z 2 − z 1 ) a 2 + b 2 + c 2 ∣ {\lvert \overrightarrow{P_1D_2} \rvert} = \lvert{ \overrightarrow{P_1P_2} \cdot \frac{\overrightarrow{P_1D_2}}{\lvert{\overrightarrow{P_1D_2}} \rvert} } \rvert = \frac{\overrightarrow{P_1D_2}}{\lvert{\overrightarrow{P_1D_2}} \rvert} \\ = \lvert{ \frac{a(x_2-x_1)+b(y_2-y_1)+c(z_2-z_1)}{\sqrt{a^2+b^2+c^2}} } \rvert P1D2 =P1P2 P1D2 P1D2 =P1D2 P1D2 =a2+b2+c2 a(x2x1)+b(y2y1)+c(z2z1)

综上,可得:
m = ∣ P 1 D → ∣ ∣ P 1 D 2 → ∣ = ∣ a x 1 + b y 1 + c z 1 + d a ( x 2 − x 1 ) + b ( y 2 − y 1 ) + c ( z 2 − z 1 ) ∣ O P → = O P 1 → + P 1 P → = O P 1 → + m ∗ P 1 P 2 → 或 ( x , y , z ) = ( x 1 , y 1 , z 1 ) + m ∗ ( x 2 − x 1 , y 2 − y 1 , z 2 − z 1 ) m = \frac{\lvert \overrightarrow {P_1D}\rvert } {\lvert \overrightarrow{P_1D_2} \rvert} = \lvert{\frac{ax_1+by_1+cz_1+d}{a(x_2-x_1)+b(y_2-y_1)+c(z_2-z_1)} } \rvert \\ \overrightarrow {OP} = \overrightarrow {OP_1} + \overrightarrow {P_1P} =\overrightarrow {OP_1} + m*\overrightarrow {P_1P_2} \\ 或 (x,y,z) = (x_1,y_1,z_1) + m*(x_2-x_1,y_2-y_1,z_2-z_1) m=P1D2 P1D =a(x2x1)+b(y2y1)+c(z2z1)ax1+by1+cz1+dOP =OP1 +P1P =OP1 +mP1P2 (x,y,z)=(x1,y1,z1)+m(x2x1,y2y1,z2z1)

编程实现

/*!
 * 求直线与平面的交点
 * @param p1
 * @param p2 直线经过的两点p1,p2
 * @param plane 平面参数 ax+by+cz+d=0
 * @param crossP 交点
 * @return true--直线与平面相交;false--直线与平面平行(或者位于平面内)
 * @author liheng
 */
bool GetLinePlaneCrossP(Eigen::Vector3f p1,Eigen::Vector3f p2,const Eigen::Vector4f& plane,Eigen::Vector3f& crossP)
{
    //求分子P1D
    auto P1D = plane[0]*p1[0] + plane[1]*p1[1] + plane[2]*p1[2]+plane[3];//ax1+by1+cz1+d//or采用向量点乘方式
    P1D = std::abs( P1D );
    auto P2D = plane[0]*p2[0] + plane[1]*p2[1] + plane[2]*p2[2]+plane[3];
    P2D = std::abs( P2D );

    //保证P2离平面比较近
    if( P1D<P2D )
    {
        std::swap(p1,p2);//点交换
        P1D = P2D;//距离交换
    }

    const Eigen::Vector3f P1P2 = p2-p1;

    //求分母P1D2
    auto P1D2 = plane[0]*P1P2[0] + plane[1]*P1P2[1] + plane[2]*P1P2[2];
    P1D2 = std::abs(P1D2);
    if( P1D2<FLT_EPSILON )
        return false;//平行


    auto m = P1D/P1D2;
    crossP = p1 + m*P1P2;

    return true;
}

下面函数同样可以
///*!
// * 求直线与平面的交点
// * @param p1
// * @param p2 直线经过的两点p1,p2
// * @param plane 平面参数 ax+by+cz+d=0
// * @param crossP 交点
// * @return true--直线与平面相交;false--直线与平面平行(或者位于平面内)
// * @author liheng
// */
//bool GetLinePlaneCrossP(const Eigen::Vector3f& p1,const Eigen::Vector3f& p2,const Eigen::Vector4f& plane,Eigen::Vector3f& crossP)
//{
//    //求分子P1D
//    auto P1D = plane[0]*p1[0] + plane[1]*p1[1] + plane[2]*p1[2]+plane[3];//ax1+by1+cz1+d//or采用向量点乘方式
//
//    const Eigen::Vector3f P1P2 = p2-p1;
//
//    //求分母P1D2
//    auto P1D2 = plane[0]*P1P2[0] + plane[1]*P1P2[1] + plane[2]*P1P2[2];
//    if( std::abs(P1D2)<FLT_EPSILON )
//        return false;//平行
//
//    auto m = P1D/P1D2;
//    crossP = p1 - m*P1P2;//注意:此处是 负号- 同时求m时无绝对值符号
//
//    return true;
//}


int main(int argc, char ** argv )
{
    Eigen::Vector3f p1(0,0,5),p2(0,0,-10),crossP;
    Eigen::Vector4f plane(0,0,1,0);//z=0
    GetLinePlaneCrossP(p1,p2,plane,crossP);
    std::cout<<"crossP:"<<crossP<<std::endl;

    return 0;
}

上面的2个函数均可以求出直线与平面交点.不论输入的两点在平面两侧或位于平面同一侧,以及两点到平面的距离排序.

粗略的python版本如下

#!/usr/bin/env python3
#coding=utf-8

#============================#
#Program:main.py
#       
#Date:20-6-23
#Author:liheng
#Version:V1.0
#============================#


import numpy as np

x1,y1,z1 = 0,0,10
x2,y2,z2 = 0,0,5
a,b,c,d = 0,0,1,0

# p1 = np.array([x1,y1,z1])#
# p2 = np.array([x2,y2,z2])
# plane_normal = np.array([a,b,c]) #a,b,c,d平面方程系数
#
# P1D = np.vdot(p1,plane_normal)+d
# P1D = np.abs(P1D)
#
# P2D = np.vdot(p2,plane_normal)+d
# P2D = np.abs(P2D)
#
# if P1D<P2D:#点1靠近平面,交换点1 2
#     p1,p2 = p2,p1
#     P1D = P2D
#
# P1D2 = np.vdot(p2-p1,plane_normal)
# P1D2 = np.abs(P1D2)
#
# n = P1D / P1D2
# p = p1 + n*(p2- p1)#所求交点
# print(p)

//or
p1 = np.array([x1,y1,z1])#
p2 = np.array([x2,y2,z2])
plane_normal = np.array([a,b,c]) #a,b,c,d平面方程系数

P1D = np.vdot(p1,plane_normal)+d
P1D2 = np.vdot(p2-p1,plane_normal)

n = P1D / P1D2
p = p1 - n*(p2- p1)#所求交点
print(p)

参考资料

1求直线与平面的交点
2.空间内直线于平面交点

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 在matlab中,要求解直线平面交点,需要先确定直线平面的参数表达式。直线可以用参数方程表示,平面可以用法向量和点的坐标表示。 假设直线的参数方程为: x = x1 + t*(x2-x1) y = y1 + t*(y2-y1) z = z1 + t*(z2-z1) 其中(x1, y1, z1)和(x2, y2, z2)是直线上任意两点的坐标,t是一个实数参数。 假设平面的法向量为(a, b, c),平面上任意一点的坐标为(x0, y0, z0),那么平面的方程可以表示为: a*(x-x0) + b*(y-y0) + c*(z-z0) = 0 有了直线方程和平面方程,我们可以将直线方程代入平面方程中,求解出t的值,再将t代回直线方程中,就可以求解直线平面交点坐标。 matlab中可以使用符号计算工具箱来求解交点坐标。具体步骤如下: 1. 定义直线平面的参数表达式。假设直线上两点的坐标为(1, 2, 3)和(4, 5, 6),平面的法向量为(1, 2, 3),平面上任意一点的坐标为(1, 1, 1),那么可以定义如下变量: syms x1 y1 z1 x2 y2 z2 t x0 y0 z0 a b c x1 = 1; y1 = 2; z1 = 3; x2 = 4; y2 = 5; z2 = 6; x0 = 1; y0 = 1; z0 = 1; a = 1; b = 2; c = 3; 2. 将直线的参数表达式代入平面方程中,解出t的值: eqn = a*(x1 + t*(x2-x1)-x0) + b*(y1 + t*(y2-y1)-y0) + c*(z1 + t*(z2-z1)-z0) == 0; tSol = solve(eqn, t); 3. 将t的值代入直线参数方程,求解交点坐标: x = x1 + tSol*(x2-x1); y = y1 + tSol*(y2-y1); z = z1 + tSol*(z2-z1); 至此,我们就求解出了直线平面交点坐标。 ### 回答2: 要求解直线平面交点,首先我们需要知道直线平面的方程。一般来说,直线可以用点向式或方向向量式表示,而平面则可以用一般式或点法式表示。 设直线的方程为 L: r = p + td,其中 r 是直线上的任一点,p 是直线上已知的一点,d 是方向向量,t 是参数。则直线上的一点可以表示为 r = p + td。 设平面的方程为 Ax + By + Cz + D = 0,其中 A、B、C 是平面法向量的分量,D 是平面截距。则平面上的一点可以表示为(x, y, z)。 接下来,我们需要求解直线平面交点。如果直线平面相交,则存在一个参数 t,使得直线上的任一点 r 满足平面方程 Ax + By + Cz + D = 0。因此,我们可以通过代入直线方程,将参数 t 消去,得到一个关于 x、y、z 的方程,解方程就能交点。 在 Matlab 中,我们可以使用符号计算工具箱中的 solve 函数来解方程。具体的步骤如下: 1. 将直线方程和平面方程用符号变量表示,例如: syms x y z t L = [1 2 3] + t*[4 5 6]; P = [2 3 4]; A = 1; B = 2; C = 3; D = 4; 2. 将直线方程代入平面方程,得到一个关于参数 t 的方程: eqn = A*(2+4*t) + B*(3+5*t) + C*(4+6*t) + D; 3. 使用 solve 函数解方程,得到参数 t 的解: t_sol = solve(eqn, t); 4. 将参数 t 的解代入直线方程,得到交点的坐标: r_sol = [1 2 3] + t_sol*[4 5 6]; 通过以上步骤,我们可以使用 Matlab 求解直线平面交点。需要注意的是,在使用 solve 函数解方程时,要注意方程是否有唯一解或多解的情况,否则可能会得到错误的结果。 ### 回答3: 在Matlab中,我们可以使用向量的方法来求解直线平面交点。 假设直线的参数方程为: x = x0 + t * a y = y0 + t * b z = z0 + t * c 其中,(x0,y0,z0)为直线上一点的坐标,(a,b,c)为直线的方向向量,t为任意一个实数。 平面的点法式方程为: Ax + By + Cz + D = 0 其中,(A,B,C)为法向量,D为平面截距。 则直线点(x,y,z)在平面上,则有: A(x0 + t * a) + B(y0 + t * b) + C(z0 + t * c) + D = 0 整理可得: t = -(Ax0 + By0 + Cz0 + D)/(Aa + Bb + Cc) 将t的解代入直线方程中,可交点的坐标。 Matlab代码实现如下: % 定义直线平面的参数 x0 = 1; y0 = 2; z0 = 3; a = 2; b = -1; c = 1; A = 3; B = -2; C = 1; D = 4; % 解参数方程和点法式方程的交点 t = -(A * x0 + B * y0 + C * z0 + D) / (A * a + B * b + C * c); x = x0 + t * a; y = y0 + t * b; z = z0 + t * c; disp(['直线平面交点为:(' num2str(x) ', ' num2str(y) ', ' num2str(z) ')']); 执行结果为: 直线平面交点为:(1.5, 1.5, 4.5) 因此,直线平面交点坐标为(1.5, 1.5, 4.5)。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值