Вот пример 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,
)
Если плоскость определена как 4-мерный вектор (нормальная форма) , нам нужно найти точку на плоскости, а затем вычислить пересечение, как и раньше (см. 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
Для дальнейшего использования это было взято из Blender и адаптировано для Python.isect_line_plane_v3()
in 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