Проецирование 3D-точек на двумерную плоскость

Пусть A - точка, для которой у меня есть 3D-координаты x, y, z, и я хочу преобразовать их в 2D-координаты: x, y. Проекция должна быть ортогональной на плоскости, заданной заданной нормой. Тривиальный случай, когда нормаль фактически является одной из осей, ее легко решить, просто устраняя координату, но как насчет других случаев, которые более вероятны?

Ответ 1

Если у вас есть целевая точка P с координатами r_P = (x,y,z) и плоскостью с нормальным n=(nx,ny,nz), вам нужно определить начало координат на плоскости, а также два ортогональных направления для x и y. Например, если ваше происхождение находится в r_O = (ox, oy, oz), а ваши две координатные оси в плоскости определяются e_1 = (ex_1,ey_1,ez_1), e_2 = (ex_2,ey_2,ez_2), тогда ортогональность имеет Dot(n,e_1)=0, Dot(n,e_2)=0, Dot(e_1,e_2)=0 (векторный точечный продукт). Обратите внимание, что все векторы направления должны быть нормированы (величина должна быть одной).

Ваша целевая точка P должна подчиняться уравнению:

r_P = r_O + t_1*e_1 + t_2*e_2 + s*n

где t_1 и t_2 - ваши 2D-координаты вдоль e_1 и e_2 и s нормальное разделение (расстояние) между плоскостью и точкой.

Там скаляры найдены проекциями:

s = Dot(n, r_P-r_O)
t_1 = Dot(e_1, r_P-r_O)    
t_2 = Dot(e_2, r_P-r_O)

Пример с началом плоскости r_O = (-1,3,1) и нормальным:

n = r_O/|r_O| = (-1/√11, 3/√11, 1/√11)

Вам нужно выбрать ортогональные направления для 2D-координат, например:

e_1 = (1/√2, 0 ,1/√2)
e_2 = (-3/√22, -2/√22, 3/√22)

такое, что Dot(n,e_1) = 0 и Dot(n,e_2) = 0 и Dot(e_1, e_2) = 0.

Двумерные координаты точки P r_P=(1,7,-3):

t_1 = Dot(e_1, r_P-r_O) = ( 1/√2,0,1/√2)·( (1,7,-3)-(-1,3,1) ) =  -√2
t_2 = Dot(e_2, r_P-r_O) = (-3/√22, -2/√22, 3/√22)·( (1,7,-3)-(-1,3,1) ) = -26/√22

и вне плоскости:

s = Dot(n, r_P-r_O) = 6/√11

Ответ 2

Найти проекцию A в нормальное направление. Затем вычтите эту проекцию из A. Остается проекция A на ортогональную плоскость.

Проекция A на единичное нормальное направление n определяется следующим образом:

(A · n) n

Если A = (x, y, z) и единичная нормаль дается выражением n = (nx, ny, nz), то проекция A на n равна

(x*nx + y*ny + z*nz) n

Таким образом, проекция A на ортогональную плоскость равна

A - (A · n) n
= (x, y, z) - (x*nx + y*ny + z*nz) (nx, ny, nz)

Например, если A = (1,2,3) и n - единичная нормаль в направлении (4,5,6), то

In [12]: A
Out[12]: array([1, 2, 3])
In [17]: d
Out[17]: array([4, 5, 6])

In [20]: n = d/sqrt(4*4 + 5*5 + 6*6)   # make n a unit vector
In [13]: n
Out[13]: array([ 0.45584231,  0.56980288,  0.68376346])

Таким образом, проекция A на ортогональную плоскость равна

In [15]: A - np.dot(A,n)*n
Out[15]: array([-0.66233766, -0.07792208,  0.50649351])

Как найти 2D-координаты:

Вам нужно определить двумерную систему координат на ортогональной плоскости. Другими словами, вам нужно определить, где находятся x-axis и y-axis. Например, вы можете определить x-axis как проекцию (1,0,0) на ортогональную плоскость (используя приведенные выше вычисления). Это будет работать, кроме как в вырожденном случае, когда (1,0,0) нормаль к плоскости.

Как только у вас есть единичные векторы для направлений оси x и y, вы можете проектировать A непосредственно на x и y. Величина этих векторов является двумерными координатами.

Например, это проекция (1,0,0) на плоскость. Возьмем это направление оси х:

In [42]: x = np.array([1,0,0])    
In [45]: x = x - np.dot(x, n) * n
In [52]: x /= sqrt((x**2).sum())   # make x a unit vector    
In [53]: x
Out[53]: array([ 0.89006056, -0.29182313, -0.35018776])

Здесь мы вычисляем направление оси y: направление y-axis должно быть перпендикулярно как нормальному направлению n, так и x. Таким образом, мы могли бы определить y как cross product n и x:

In [68]: y = np.cross(n, x)

In [69]: y
Out[69]: array([ -2.77555756e-17,   7.68221280e-01,  -6.40184400e-01])

Итак, вот координаты для A в плоскости:

In [70]: np.dot(A, x), np.dot(A, y)
Out[70]: (-0.74414898890755965, -0.38411063979868798)