ПрограммированиеFAQ

Пересечение прямой и плоскости

Пересечение: Прямая (или отрезок) и плоскость. Плоскость задана тремя точками, прямая (или отрезок) начальной и конечными точками. Очевидно, эта задача, как и многие подобные ей, может быть решена путем составления системы. Хотелось бы предложить более геометричный метод, который гораздо удобней в большинстве случаев.

Будем обозначать A,B,C - точки плоскости, X,Y - точки прямой(концы отрезка),  DotProduct - скалярное произведение,  VectorProduct - векторное произведение. O - искомое множество точек пересечения

N = VectorProduct ( B - A, C - A )
N = N / | N |  - нормаль к плоскости  // в принципе это можно и не делать
V = A - X
// расстояние до плоскости по нормали
d = DotProduct ( N, V ) 
W = Y - X
// приближение к плоскости по нормали при прохождении отрезка
e =  DotProduct ( N, W )

if( e!=0 )
  O = X + W * d/e;          // одна точка
else if( d==0)
  O =X + W * (anything)    // прямая принадлежит плоскости
else
  O = empty;                // прямая параллельна плоскости
-----------------------------------------------------------------------

Было запрограммированно в Делфи следующим образом:

type
  xyz = record
  x,y,z : real;
  end;

var
  NotIntersectPlaneLine:boolean;

Function CreateVector(A,B:xyz):xyz;
//Функция создает вектор из двух точек A,B.
//АВ = (В.х-А.х,В.y-А.y,В.z-А.z)
begin
CreateVector.x := B.x-A.x;
CreateVector.y := B.y-A.y;
CreateVector.z := B.z-A.z;
end;

Function  VectorProduct(A,B:xyz):xyz;
//Векторное произведение
begin
VP.x := A.y*B.z-B.y*A.z;
VP.y := A.z*B.x-B.z*A.x;
VP.z := A.x*B.y-B.x*A.y;
end;

Function  DotProduct(A,B:xyz):real;
//Скалярное произведение
begin
SP := A.x*B.x + A.y*B.y + A.z*B.z;
end;

Procedure Normalize(var A:xyz);
//Привести длину вектора к единице
var R,mlr:real;
begin
mlr := sqrt(sqr(A.x)+sqr(A.y)+sqr(A.z));

A.x := A.x/mlr;
A.y := A.y/mlr;
A.z := A.z/mlr;
end;

Function PlaneIntersectLine(A,B,C,X,Y:xyz):xyz;
//Итак на входе у нас три точки плоскости A,B,C и две точки прямой X,Y
var N,V,W : xyz;
    e,d : real;
begin
NotIntersectPlaneLine := true;

N :=  VectorProduct(CreateVector(A,B),CreateVector(A,C));
Normalize(N);
V := CreateVector(X,A);
// расстояние до плоскости по нормали
d :=  DotProduct(N,V);
W := CreateVector(X,Y);
// приближение к плоскости по нормали при прохождении отрезка
e :=  DotProduct(N,W);

if e<>0 then // одна точка,
//в любом другом случае(принадлежит, или параллельна плоскости)
//флаг сигнализирующий что единственная точка не найдена будет правдой
begin
PlaneIntersectLine.x := X.x  +  W.x*d/e;
PlaneIntersectLine.y := X.y  +  W.y*d/e;
PlaneIntersectLine.z := X.z  +  W.z*d/e;
NotIntersectPlaneLine := false;
end;
end;

Проект делфи как пример, где указываются точки плоскости и прямой можно скачать по этому адресу
http://www.gamedev.ru/download/?id=7125

8 апреля 2008 (Обновление: 11 мар 2024)