Let A be a point for which I have the 3D coordinates x, y, z and I want to transform them into 2D coordinates: x, y. The projection shall be orthogonal on a plane defined by a given normal. The trivial case, where the normal is actually one of the axes, it's easy to solve, simply eliminating a coordinate, but how about the other cases, which are more likely to happen?
问题:
回答1:
If you have your target point P with coordinates r_P = (x,y,z)
and a plane with normal n=(nx,ny,nz)
you need to define an origin on the plane, as well as two orthogonal directions for x
and y
. For example if your origin is at r_O = (ox, oy, oz)
and your two coordinate axis in the plane are defined by e_1 = (ex_1,ey_1,ez_1)
, e_2 = (ex_2,ey_2,ez_2)
then orthogonality has that Dot(n,e_1)=0
, Dot(n,e_2)=0
, Dot(e_1,e_2)=0
(vector dot product). Note that all the direction vectors should be normalized (magnitude should be one).
Your target point P must obey the equation:
r_P = r_O + t_1*e_1 + t_2*e_2 + s*n
where t_1
and t_2
are your 2D coordinates along e_1
and e_2
and s
the normal separation (distance) between the plane and the point.
There scalars are found by projections:
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)
Example with a plane origin r_O = (-1,3,1)
and normal:
n = r_O/|r_O| = (-1/√11, 3/√11, 1/√11)
You have to pick orthogonal directions for the 2D coordinates, for example:
e_1 = (1/√2, 0 ,1/√2)
e_2 = (-3/√22, -2/√22, 3/√22)
such that Dot(n,e_1) = 0
and Dot(n,e_2) = 0
and Dot(e_1, e_2) = 0
.
The 2D coordinates of a point P r_P=(1,7,-3)
are:
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
and the out of plane separation:
s = Dot(n, r_P-r_O) = 6/√11
回答2:
Find the projection of A
onto the normal direction. Then subtract that projection from A
. What is left is the projection of A
onto the orthogonal plane.
The projection of A onto the unit normal direction n
is given by:
(A · n) n
If A = (x, y, z)
and the unit normal is given by n = (nx, ny, nz)
, then the projection of A onto n
is
(x*nx + y*ny + z*nz) n
So the projection of A onto the orthogonal plane is
A - (A · n) n
= (x, y, z) - (x*nx + y*ny + z*nz) (nx, ny, nz)
For example, if A = (1,2,3) and n is the unit normal in direction (4,5,6), then
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])
So the projection of A onto the orthogonal plane is
In [15]: A - np.dot(A,n)*n
Out[15]: array([-0.66233766, -0.07792208, 0.50649351])
How to find 2D coordinates:
You'll need to define a 2D coordinate system on the orthogonal plane. In other words, you need to define where the x-axis
and y-axis
are. For example, you could define the x-axis
to be the projection of (1,0,0) onto the orthogonal plane (using the computation shown above). This will work except in the degenerate case where (1,0,0) is normal to the plane.
Once you have unit vectors for the x
and y
axis directions, then you could project A
directly onto x
and y
. The magnitude of those vectors are the 2D coordinates.
For example, this is the projection of (1,0,0) onto the plane. We take this to be the x-axis direction:
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])
Here we compute the y-axis direction: The y-axis
direction must be perpendicular to both the normal direction n
and to x
. So we could define y
to be the cross product of n
and x
:
In [68]: y = np.cross(n, x)
In [69]: y
Out[69]: array([ -2.77555756e-17, 7.68221280e-01, -6.40184400e-01])
So here are the coordinates for A
in the plane:
In [70]: np.dot(A, x), np.dot(A, y)
Out[70]: (-0.74414898890755965, -0.38411063979868798)