Using Numpy I want to transform position vectors between coordinate systems.
To help visualize the problem: http://tube.geogebra.org/student/m1097765
I have two planes in 3D space. Each plane is defined by its center:
C[0] = (X0, Y0, Z0)
C[1] = (X1, Y1, Z1)
(X,Y,Z are referred to a global coordinate system)
C = np.array([[0,0,0],[-4,2,1]])
and its normal vector:
H[0] = (cos(alpha[0])*sin(A[0]), cos(alpha[0])*cos(A[0]), sin(A[0])
H[1] = (cos(alpha[1])*sin(A[1]), cos(alpha[1])*cos(A[1]), sin(A[1])
alpha
= elevation angle
A
= azimuth angle
H = np.array([[-0.23, -0.45, 0.86], [-0.12, -0.24, 0.86]])
I have a point p(xp, yp, 0)
lying on plane 0
(xp
, yp
are referred to a local coordinate system with center C[0]
and its xyz
axes are aligned with the global XYZ
axes when alpha = A = 0
)
I transform from the local coordinate system of plane 0 to global with the following functions:
import numpy as np
def rotateAxisX(alpha):
'''
Rotation about x axis
:param alpha: plane altitude angle in degrees
:return: x-axis rotation matrix
'''
rotX = np.array([[1, 0, 0], [0, np.cos(np.deg2rad(alpha)), np.sin(np.deg2rad(alpha))], [0, -np.sin(np.deg2rad(alpha)), np.cos(np.deg2rad(alpha))]])
return rotX
def rotateAxisZ(A):
'''
Rotation about z axis
:param A: plane azimuth angle in degrees
:return: z-axis rotation matrix
'''
rotZ = np.array([[np.cos(np.deg2rad(A)), np.sin(np.deg2rad(A)), 0], [-np.sin(np.deg2rad(A)), np.cos(np.deg2rad(A)), 0], [0, 0, 1]])
return rotZ
def local2Global(positionVector, planeNormalVector, positionVectorLocal):
'''
Convert point from plane's local coordinate system to global coordinate system
:param positionVector: plane center in global coordinates
:param planeNormalVector: the normal vector of the plane
:param positionVectorLocal: a point on plane (xp,yp,0) with respect to the local coordinate system of the plane
:return: the position vector of the point in global coordinates
>>> C = np.array([-10,20,1200])
>>> H = np.array([-0.23, -0.45, 0.86])
>>> p = np.array([-150, -1.5, 0])
>>> P = local2Global(C, H, p)
>>> np.linalg.norm(P-C) == np.linalg.norm(p)
True
'''
alpha = np.rad2deg(np.arcsin(planeNormalVector[2]))
A = np.where(planeNormalVector[1] > 0, np.rad2deg(np.arccos(planeNormalVector[1] / np.cos(np.deg2rad(alpha)))), 360 - np.rad2deg(np.arccos(planeNormalVector[1] / np.cos(np.deg2rad(alpha)))))
positionVectorGlobal = positionVector + np.dot(np.dot(rotateAxisZ(A), rotateAxisX(90 - alpha)), positionVectorLocal)
return positionVectorGlobal
The above seems to work as expected.
Then I'm computing the intersection of a line passing from a point on plane 0 p(xp,yp,0)
and has the direction vector of S = (0.56, -0.77, 0.3)
>>> C = np.array([[0,0,0],[-4,2,1]]) # plane centers
>>> H = np.array([[-0.23, -0.45, 0.86], [-0.12, -0.24, 0.86]]) # plane normal vectors
>>> S = np.array([0.56, -0.77, 0.3]) # a direction vector
>>> p = np.array([-1.5, -1.5, 0]) # a point on a plane
>>> intersectingPlaneIndex = 0 # choose intersecting plane, this plane has the point p on it
>>> intersectedPlaneIndex = 1 # this plane intersects with the line passing from p with direction vector s
>>> P = local2Global(C[intersectingPlaneIndex], H[intersectingPlaneIndex], p) # point p in global coordinates
>>> np.isclose(np.linalg.norm(p), np.linalg.norm(P - C[intersectingPlaneIndex]), 10e-8)
True
So the first transformation is successful.
Now let's find intersection point E in global coordinates
>>> t = np.dot(H[intersectedPlaneIndex], C[intersectedPlaneIndex, :] - P) / np.dot(H[intersectedPlaneIndex], S)
>>> E = P + S * t
>>> np.around(E, 2)
array([ 2.73, -0.67, 1.19])
So far so good, I found the point E
(global coordinates) which lies on plane 1.
The problem:
How can I convert point E
from global coordinates to the coordinate system of plane 1 and obtain e(xe, ye, 0)
?
I tried:
def global2Local(positionVector, planeNormalVector, positionVectorGlobal):
'''
Convert point from global coordinate system to plane's local coordinate system
:param positionVector: plane center in global coordinates
:param planeNormalVector: the normal vector of the plane
:param positionVectorGlobal: a point in global coordinates
:note: This function translates the given position vector by the positionVector and rotates the basis axis in order to obtain the positionVectorCoordinates in plane's coordinate system
:warning: it does not function as it should
'''
alpha = np.rad2deg(np.arcsin(planeNormalVector[2]))
A = np.where(planeNormalVector[1] > 0, np.rad2deg(np.arccos(planeNormalVector[1] / np.cos(np.deg2rad(alpha)))), 360 - np.rad2deg(np.arccos(planeNormalVector[1] / np.cos(np.deg2rad(alpha)))))
positionVectorLocal = np.dot(np.dot(np.linalg.inv(rotateAxisZ(A)), np.linalg.inv(rotateAxisX(90 - alpha))), positionVectorGlobal - positionVector) + positionVectorGlobal
return positionVectorLocal
And:
>>> e = global2Local(C[intersectedPlaneIndex], H[intersectedPlaneIndex], E)
>>> e
array([ -2.54839059e+00, -5.48380179e+00, -1.42292121e-03])
In first look this seem ok, as long as e[2] is near zero but,
>>> np.linalg.norm(E-C[intersectedPlaneIndex])
7.2440723159783182
>>> np.linalg.norm(e)
6.0470140356703537
So the transformation is wrong. Any ideas?
If, in 2D the origin of a body moves by translation t in its original reference frame and rotates by angle R=R(θ), then the transformation that converts positional coordinates from the new coordinate frame to the original coordinate frame is given by Tp(x)=Rx+t.
The transformation matrix, between coordinate systems having differing orientations is called the rotation matrix. This transforms the components of any vector with respect to one coordinate frame to the components with respect to a second coordinate frame rotated with respect to the first frame.
transData converts values in data coordinates to display coordinates and ax. transData. inversed() is a matplotlib. transforms. Transform that goes from display coordinates to data coordinates.
I'd recommend reading this and this. For the first one, look at the concept of homogenous coordinates, as for spatial transforms with different origins that is kinda needed. For the second one, look at how the camera "look-at" transform is performed. As long as you have the orthonormal basis vectors (easy enough to get from the angles), you can use the equations in the second one to do the transform. The post linked in the comments seems to cover similar material.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With