當從外界讀入STL等三維模型時,其會按照它內部的坐標位置進行顯示。因此它的位置和大小是確定的。但是在實際應用中,有可能需要人為地對這個模型在空間中進行旋轉、平移或縮放等操作。VTK中有許多和旋轉、平移相關的函數,下面一一進行測試。
- RotateX、RotateY、RotateZ(繞自身坐標軸旋轉)
Rotate the Prop3D in degrees about the X/Y/Z axis using the right hand rule. The axis is the Prop3D's X/Y/Z axis, which can change as other rotations are performed. 即前一次的旋轉會影響到后一次。
假設物體坐標系開始與世界坐標系重合,先后調用RotateZ(90)、RotateX(90)的結果如下圖所示:

使用GetOrientation可以獲取當前物體的姿態信息,結果為(90, 0, 90)。GetOrientation:Returns the orientation of the Prop3D as s vector of X,Y and Z rotation. The ordering in which these rotations must be done to generate the same matrix is RotateZ, RotateX, and finally RotateY. 即按照Z-X-Y的順序將世界坐標系繞自身旋轉即可得到當前姿態。
- RotateWXYZ(繞世界坐標系旋轉)
Rotate the Prop3D in degrees about an arbitrary axis specified by the last three arguments. The axis is specified in world coordinates. 該函數的后三個參數指定旋轉方向(可以是任意方向,不一定非得是坐標軸方向)。如按世界坐標系的X軸旋轉可寫為RotateWXYZ(deg, 1, 0, 0),按世界坐標系的Z軸旋轉可寫為RotateWXYZ(deg, 0, 0, 1)。同樣是先后調用RotateWXYZ(90,0,0,1)、RotateWXYZ(90,1,0,0)得到的結果如下:

此時調用GetOrientation返回值是:(0, -90, 90),即將世界坐標系先繞自身Z軸旋轉90°,再繞X軸旋轉0°,最后繞Y軸旋轉-90°即可到達當前姿態。
- SetOrientation(x, y, z) —— 通過先繞Z軸,然后繞X軸,最后繞Y軸旋轉,從而來確定Prop的方向。
- AddOrientation(a1, a2,a3) —— 在當前Prop方向增加a1, a2, a3增量。
- SetOrigin(設置旋轉中心點)
Set the origin of the Prop3D. This is the point about which all rotations take place. 調用RotateX或RotateWXYZ等旋轉函數時會默認旋轉中心在原點,即會繞着(0, 0, 0)沿着某一方向旋轉。通過調用SetOrigin函數可以改變旋轉點的位置。例如一個長寬高都是100的立方體,繞自身Z軸旋轉45°,下圖左邊是默認旋轉中心在原點,右邊是調用SetOrigin設置旋轉中心在(50,0,0)的結果


- SetPosition、AddPosition(設置物體在世界坐標系中的位置)
SetPosition(x, y, z)—— 指定vtkProp3D對象在世界坐標系中的位置。AddPosition(deltaX, deltaY, deltaZ) —— 用指定的X、Y、Z三個方向的增量來平移Prop。如下圖中立方體開始在原點處,調用SetPosition(50,0,0)后其位置變為(50,0,0)。可以通過GetPosition函數查看物體在世界坐標系中的位置。

- SetUserTransform、GetUserTransform
The most important aspect to applying transformation matrices is to understand the order in which the transformations are applied. Most of the methods for manipulating this transformation, e.g. Translate, Rotate, and Concatenate, can operate in either PreMultiply (the default) or PostMultiply mode. In PreMultiply mode, the translation, concatenation, etc. will occur before any transformations which are represented by the current matrix. In PostMultiply mode, the additional transformation will occur after any transformations represented by the current matrix.
進行變換時的順序非常重要,對於變換矩陣VTK里是用以下的順序來應用這些變換的:
$$T_T=T(p_x+o_x,p_y+o_y,p_z+o_z)\cdot R_Z\cdot R_X\cdot R_Y\cdot S(s_x,s_y,s_z)\cdot T(-o_x,-o_y,-o_z)$$
1. 移動Prop到原點;
2. 縮放;
3. 繞Y軸旋轉;
4. 繞X軸旋轉;
5. 繞Z軸旋轉;
6. 從原點中移動回原來的位置;
7. 平移。
因為默認是進行左乘所以進行變換時先調用的最后才變換(即逆序),下面的代碼實現了公式中的變換:
vtkTransform *myTrans = vtkTransform::New (); myTrans->Translate (position[0],position[1],position[2]); myTrans->Translate (origin[0],origin[1],origin[2]); myTrans->RotateZ (orientation[2]); myTrans->RotateX (orientation[0]); myTrans->RotateZ (orientation[1]; myTrans->Scale (scale[0],scale[1],scale[2]); myTrans->Translate (-origin[0],-origin[1],-origin[2]);
actor->SetUserTransform(myTrans);
vtkTransform::PreMultiply()用於設置左乘. Sets the internal state of the transform to PreMultiply. All subsequent operations will occur before those already represented in the current transformation. In homogeneous matrix notation, M = M*A where M is the current transformation matrix and A is the applied matrix. The default is PreMultiply.
vtkTransform::PostMultiply()用於設置右乘,Sets the internal state of the transform to PostMultiply. M = A*M where M is the current transformation matrix and A is the applied matrix.
如下所示,左邊平面先旋轉45°再沿X軸正方向移動2個單位;右邊平面先沿X軸正方向移動2個單位,然后旋轉45°(旋轉中心在原點)。可以看出函數調用順序顛倒一下產生了截然不同的兩種結果(We always specify transformations in the reverse order of their application)


- SetUserMatrix、GetUserMatrix
The UserMatrix can be used in place of UserTransform. Transformation matrices can be combined by matrix multiplication to achieve combinations of translation, rotation, and scaling. It is possible for a single transformation matrix to represent all types of transformation simultaneously.
下面代碼將物體繞Z軸旋轉45°,並移動到(50, 50, 50)處
trans = [0.707107, -0.707107, 0, 50, 0.707107, 0.707107, 0, 50, 0, 0, 1, 50, 0, 0, 0, 1] mat = vtk.vtkMatrix4x4() mat.DeepCopy(trans) actor.SetUserMatrix(mat)

- GetMatrix
UserMatrix is one you can assign yourself to an actor or a top-level composite assembly of actors. Matrix is computed automatically from any position, rotation or scale the actor may have, in addition to the UserMatrix. Calling GetMatrix should always give you the exact matrix applied to an actor to get it to from whatever its own "model space" is to VTK world space. UserMatrix is nullptr until you set it, or until the actor is added as part of an assembly, where the parent assembly may set user matrices directly for its constituent parts. You can't set the matrix directly, but you can set the UserMatrix directly.
GetMatrix與GetUserMatrix函數有很大區別:GetUserMatrix用來獲取用戶設置的變換矩陣,如果用戶沒有設置則會返回空,而GetMatrix則始終都會返回場景中物體相對世界坐標系的變換矩陣。
import vtk # create a rendering window and renderer ren = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren) # create a renderwindowinteractor iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) # create plane source plane = vtk.vtkPlaneSource() plane.SetXResolution(1) plane.SetYResolution(1) plane.SetCenter(0,0,0) plane.SetNormal(0,0,1) # mapper mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(plane.GetOutputPort()) # actor actor = vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetRepresentationToWireframe() # assign actor to the renderer ren.AddActor(actor) # create coordinate axes in the render window axes = vtk.vtkAxesActor() axes.SetTotalLength(1, 1, 1) axes.SetShaftType(0) axes.SetAxisLabels(0) axes.SetCylinderRadius(0.02) ren.AddActor(axes) style = vtk.vtkInteractorStyleTrackballCamera() style.SetDefaultRenderer(ren) iren.SetInteractorStyle(style) actor.RotateZ(45) actor.SetPosition(2,0,0) print actor.GetMatrix() print actor.GetUserMatrix() print actor.GetUserTransform () print '---------------------------' trans = vtk.vtkTransform() trans.RotateZ(-45) trans.Translate(-2, 0, 0) actor.SetUserTransform(trans) print actor.GetMatrix() print actor.GetUserMatrix() print actor.GetUserTransform () camera = vtk.vtkCamera() camera.ParallelProjectionOn() ren.SetActiveCamera(camera) ren.ResetCamera() # enable user interface interactor iren.Initialize() renWin.Render() iren.Start()


先將平面繞Z軸旋轉45°,再移動到(2,0,0)位置,三個函數輸出如下圖所示。由於沒有顯式調用SetUserMatrix或SetUserTransform設置UserMatrix,因此GetUserMatrix和GetUserTransform函數返回均為None。

然后將平面沿X軸負方向平移2個單位,再繞Z軸旋轉-45°,將平面變換回初始位置(如果想先旋轉再平移將其變換回初始位置,則要重新設置旋轉中心,否則旋轉時會繞原點旋轉)。從下圖可以看出GetMatrix函數返回了單位矩陣,即現在平面的位置和姿態與世界坐標系一致。GetUerMatrix和GetUserTransform返回的變換矩陣一樣:T=Rz(-45°)·T(-2, 0, 0),為平移和旋轉所構成的變換矩陣。


平面由初始位置變換到新位置再變換回去,兩次操作互逆,因此變換矩陣互為逆矩陣。
注意:已知B→A的齊次變換矩陣T,則A→B的齊次變換矩陣T-1如下:


參考:
