Numpy - 坐标系之间的转换

8
使用Numpy,我希望将坐标系之间的位置矢量进行转换。
为了更好地可视化问题: http://tube.geogebra.org/student/m1097765
我有两个位于3D空间中的平面。 每个平面都由其中心定义:
C[0] = (X0, Y0, Z0)

C[1] = (X1, Y1, Z1)

(X,Y,Z被称为全局坐标系)
C = np.array([[0,0,0],[-4,2,1]])

以及它的法向量:

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 = 仰角

A = 方位角

H = np.array([[-0.23, -0.45, 0.86], [-0.12, -0.24, 0.86]])

我有一个点p(xp, yp, 0)位于平面0上(xpyp是相对于本地坐标系的,中心为C[0],当alpha = A = 0时,其xyz轴与全局XYZ轴对齐)

我使用以下函数从平面0的本地坐标系转换到全局坐标系:

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

上述内容似乎按预期运作。

然后我计算通过平面0上的一点 p(xp,yp,0) 并具有方向向量S = (0.56,-0.77,0.3) 的直线与平面1的交点。

>>> 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

第一次转换成功。

现在让我们在全局坐标系中找到交点E。

>>> 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])

目前为止,我已经找到了平面1上的一个点 E(全局坐标)。

问题是:

我该如何将点 E 从全局坐标转换为平面1的坐标系,并获得 e(xe, ye, 0)

我尝试过:

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

并且:

>>> e = global2Local(C[intersectedPlaneIndex], H[intersectedPlaneIndex], E)
>>> e
array([ -2.54839059e+00,  -5.48380179e+00,  -1.42292121e-03])

乍一看这似乎没问题,只要e [2]接近于零,但是...

>>> np.linalg.norm(E-C[intersectedPlaneIndex])
7.2440723159783182
>>> np.linalg.norm(e)
6.0470140356703537

所以这个转换是错误的。有什么想法吗?

2
我使用这里描述的方法来执行这种转换。 - Saullo G. P. Castro
你在 positionVectorLocal 这一行中塞入了太多的内容,很难理解它在做什么。 - hpaulj
增加了更多细节并修改了global2Local模块。 - T81
1个回答

1
我建议阅读thisthis。对于第一个链接,请查看齐次坐标的概念,因为空间变换需要使用不同原点。对于第二个链接,请查看如何执行相机“look-at”变换。只要你有正交基向量(从角度很容易获得),你就可以使用第二个链接中的方程式进行变换。评论中链接的帖子似乎涵盖了类似的材料。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接