三维线平面交点

jt7*_*t78 29 3d intersection line plane

如果给定一条线(由线上的矢量或两个点表示),我如何找到线与平面相交的点?我已经找到了大量的资源,但我无法理解那里的方程(它们似乎不是标准的代数).我想要一个标准编程语言(我使用Java)可以解释的等式(无论多长时间).

ide*_*n42 33

下面是一个Python示例,它可以找到直线和平面的交点.

在平面可以是点和法线,或4d矢量(正常形式)的情况下,在下面的示例中(提供两者的代码).

另请注意,此函数计算一个值,表示该点在该行的位置(fac在下面的代码中调用).您可能也希望返回此值,因为从0到1的值与线段相交 - 这可能对调用者有用.

代码注释中提到的其他详细信息.


注意:此示例使用纯函数,没有任何依赖性 - 使其易于移动到其他语言.对于Vector数据类型和运算符重载,它可以更简洁(包括在下面的示例中).

# intersection function
def isect_line_plane_v3(p0, p1, p_co, p_no, epsilon=1e-6):
    """
    p0, p1: Define the line.
    p_co, p_no: define the plane:
        p_co Is a point on the plane (plane coordinate).
        p_no Is a normal vector defining the plane direction;
             (does not need to be normalized).

    Return a Vector or None (when the intersection can't be found).
    """

    u = sub_v3v3(p1, p0)
    dot = dot_v3v3(p_no, u)

    if abs(dot) > epsilon:
        # The factor of the point between p0 -> p1 (0 - 1)
        # if 'fac' is between (0 - 1) the point intersects with the segment.
        # Otherwise:
        #  < 0.0: behind p0.
        #  > 1.0: infront of p1.
        w = sub_v3v3(p0, p_co)
        fac = -dot_v3v3(p_no, w) / dot
        u = mul_v3_fl(u, fac)
        return add_v3v3(p0, u)
    else:
        # The segment is parallel to plane.
        return None

# ----------------------
# generic math functions

def add_v3v3(v0, v1):
    return (
        v0[0] + v1[0],
        v0[1] + v1[1],
        v0[2] + v1[2],
        )


def sub_v3v3(v0, v1):
    return (
        v0[0] - v1[0],
        v0[1] - v1[1],
        v0[2] - v1[2],
        )


def dot_v3v3(v0, v1):
    return (
        (v0[0] * v1[0]) +
        (v0[1] * v1[1]) +
        (v0[2] * v1[2])
        )


def len_squared_v3(v0):
    return dot_v3v3(v0, v0)


def mul_v3_fl(v0, f):
    return (
        v0[0] * f,
        v0[1] * f,
        v0[2] * f,
        )
Run Code Online (Sandbox Code Playgroud)

如果将平面定义为4d向量(法线形式),我们需要在平面上找到一个点,然后像以前一样计算交点(参见p_co赋值).

def isect_line_plane_v3_4d(p0, p1, plane, epsilon=1e-6):
    u = sub_v3v3(p1, p0)
    dot = dot_v3v3(plane, u)

    if abs(dot) > epsilon:
        # Calculate a point on the plane
        # (divide can be omitted for unit hessian-normal form).
        p_co = mul_v3_fl(plane, -plane[3] / len_squared_v3(plane))

        w = sub_v3v3(p0, p_co)
        fac = -dot_v3v3(plane, w) / dot
        u = mul_v3_fl(u, fac)
        return add_v3v3(p0, u)
    else:
        return None
Run Code Online (Sandbox Code Playgroud)

为了进一步参考,这是从Blender中获取并适用于Python. isect_line_plane_v3()math_geom.c中


为清楚起见,这里是使用mathutils API的版本(可以为运算符重载的其他数学库修改).

# point-normal plane
def isect_line_plane_v3(p0, p1, p_co, p_no, epsilon=1e-6):
    u = p1 - p0
    dot = p_no * u
    if abs(dot) > epsilon:
        w = p0 - p_co
        fac = -(plane * w) / dot
        return p0 + (u * fac)
    else:
        return None


# normal-form plane
def isect_line_plane_v3_4d(p0, p1, plane, epsilon=1e-6):
    u = p1 - p0
    dot = plane.xyz * u
    if abs(dot) > epsilon:
        p_co = plane.xyz * (-plane[3] / plane.xyz.length_squared)

        w = p0 - p_co
        fac = -(plane * w) / dot
        return p0 + (u * fac)
    else:
        return None
Run Code Online (Sandbox Code Playgroud)

  • 最后,实际上有效的交叉方法!男人......我在墙上撞了很长时间试图修改我的代码以获得联系,谢谢先生. (3认同)

Joh*_*ohn 18

你需要考虑三种情况:

  • 平面与线平行,线不在平面内(没有交叉点)
  • 平面与线不平行(一个交点)
  • 平面包含线(线在其上的每个点相交)

你可以用paramaterized形式表达这一行,就像这里:

http://answers.yahoo.com/question/index?qid=20080830195656AA3aEBr

本讲座的前几页对飞机也是如此:

http://math.mit.edu/classes/18.02/notes/lecture5compl-09.pdf

如果平面的法线垂直于沿线的方向,则您有一个边缘情况,需要查看它是否完全相交,或者是否位于平面内.

否则,你有一个交点,可以解决它.

我知道这不是代码,但为了获得一个强大的解决方案,您可能希望将其放在应用程序的上下文中.

编辑:这是一个恰好有一个交叉点的例子.假设您从第一个链接中的参数化方程开始:

x = 5 - 13t
y = 5 - 11t
z = 5 - 8t
Run Code Online (Sandbox Code Playgroud)

参数t可以是任何东西.(x, y, z)满足这些方程的所有(无限)组包括线.然后,如果您有飞机的等式,请说:

x + 2y + 2z = 5
Run Code Online (Sandbox Code Playgroud)

(摘自这里)可以替代方程x,yz上述入公式为平面,这是现在在唯一的参数t.解决t.这是t位于平面中的那条线的特定值.然后你就可以解决x,y以及z通过返回到线方程和代t回.


ZGo*_*ock 12

这是Java中的一种方法,用于查找直线与平面之间的交集.有些矢量方法不包括在内,但它们的功能非常自我解释.

/**
 * Determines the point of intersection between a plane defined by a point and a normal vector and a line defined by a point and a direction vector.
 *
 * @param planePoint    A point on the plane.
 * @param planeNormal   The normal vector of the plane.
 * @param linePoint     A point on the line.
 * @param lineDirection The direction vector of the line.
 * @return The point of intersection between the line and the plane, null if the line is parallel to the plane.
 */
public static Vector lineIntersection(Vector planePoint, Vector planeNormal, Vector linePoint, Vector lineDirection) {
    if (planeNormal.dot(lineDirection.normalize()) == 0) {
        return null;
    }

    double t = (planeNormal.dot(planePoint) - planeNormal.dot(linePoint)) / planeNormal.dot(lineDirection.normalize());
    return linePoint.plus(lineDirection.normalize().scale(t));
}
Run Code Online (Sandbox Code Playgroud)


Tim*_*mSC 11

使用numpy和python:

#Based on http://geomalgorithms.com/a05-_intersect-1.html
from __future__ import print_function
import numpy as np

epsilon=1e-6

#Define plane
planeNormal = np.array([0, 0, 1])
planePoint = np.array([0, 0, 5]) #Any point on the plane

#Define ray
rayDirection = np.array([0, -1, -1])
rayPoint = np.array([0, 0, 10]) #Any point along the ray

ndotu = planeNormal.dot(rayDirection) 

if abs(ndotu) < epsilon:
    print ("no intersection or line is within plane")

w = rayPoint - planePoint
si = -planeNormal.dot(w) / ndotu
Psi = w + si * rayDirection + planePoint

print ("intersection at", Psi)
Run Code Online (Sandbox Code Playgroud)


DNa*_*Nax 5

如果您有两个点 p 和 q 定义一条线,以及一个平面的一般笛卡尔形式 ax+by+cz+d = 0,则可以使用参数化方法。

如果您出于编码目的需要它,这里有一个 javascript 片段:

/**
* findLinePlaneIntersectionCoords (to avoid requiring unnecessary instantiation)
* Given points p with px py pz and q that define a line, and the plane
* of formula ax+by+cz+d = 0, returns the intersection point or null if none.
*/
function findLinePlaneIntersectionCoords(px, py, pz, qx, qy, qz, a, b, c, d) {
    var tDenom = a*(qx-px) + b*(qy-py) + c*(qz-pz);
    if (tDenom == 0) return null;

    var t = - ( a*px + b*py + c*pz + d ) / tDenom;

    return {
        x: (px+t*(qx-px)),
        y: (py+t*(qy-py)),
        z: (pz+t*(qz-pz))
    };
}

// Example (plane at y = 10  and perpendicular line from the origin)
console.log(JSON.stringify(findLinePlaneIntersectionCoords(0,0,0,0,1,0,0,1,0,-10)));

// Example (no intersection, plane and line are parallel)
console.log(JSON.stringify(findLinePlaneIntersectionCoords(0,0,0,0,0,1,0,1,0,-10)));
Run Code Online (Sandbox Code Playgroud)

  • 应该“var t = - (a*px + b*py + c*pz + d) / tDenom;” 实际上要减去 d 吗?所以 ... var t = - ( a*px + b*py + c*pz - d ) / tDenom; (2认同)