Rotating Slice around Axis of Model

Hi all,
Having a slight problem and can’t for the life of me figure it out. Was hoping that one of you could help me out. Let me explain the problem.

I have a 3d model loaded into the scene. That model has two transforms applied to it.

RegistrationTransform->RotationTransform->Model

The registration transform registers the model to image space(offset and rotation). The RotationTransform controls how the model is rotated about its axes. I am trying to make a slider which will rotate the model about the model Y axis and have the axial slice follow this rotation. Currently I have a slider which is connected to the following method and the model rotation is working perfectly by applying a Y rotation to the RotationTransform. See code:

void onModelRotationSliderChanged(double value){
     vtkMRMLLinearTransformNode* registrationTransform = this->mrmlScene()->GetNodeByID('vtkMRMLLinearTransformNode1');
     vtkMRMLLinearTransformNode* rotationTransform = this->mrmlScene()->GetNodeByID('vtkMRMLLinearTransformNode2');
     rotationTransform->RotateWXYZ(d->previousRotation - value, 0, 1, 0);
     d->previousRotation = value;
}

The above code works perfectly. No matter what RegistrationTransform is used the model always rotates around the model Y axis. The problem I am having is getting the slice to then follow that same rotation. I have the following code which I added to the end of the above function, but it doesn’t rotate the axial slice in the desired manner:

vtkSmartPointer<vtkMatrix4x4> currentSliceToRAS = d->redViewer->GetSliceToRAS();
vtkSmartPointer<vtkMatrix4x4> registrationMatrix = registrationTransform->GetMatrixTransformToParent();
vtkSmartPointer<vtkMatrix4x4> newResliceMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
newResliceMatrix->Multiply4x4(rotationTransform->GetMatrix(), registrationMatrix, newResliceMatrix);
currentSliceToRAS->SetElement(0, 0, newResliceMatrix->GetElement(0, 0));
currentSliceToRAS->SetElement(0, 1, newResliceMatrix->GetElement(0, 1));
currentSliceToRAS->SetElement(0, 2, newResliceMatrix->GetElement(0, 2));
currentSliceToRAS->SetElement(0, 3, registrationMatrix->GetElement(0, 3));
currentSliceToRAS->SetElement(1, 0, newResliceMatrix->GetElement(1, 0));
currentSliceToRAS->SetElement(1, 1, newResliceMatrix->GetElement(1, 1));
currentSliceToRAS->SetElement(1, 2, newResliceMatrix->GetElement(1, 2));
currentSliceToRAS->SetElement(1, 3, registrationMatrix->GetElement(1, 3));
currentSliceToRAS->SetElement(2, 0, newResliceMatrix->GetElement(2, 0));
currentSliceToRAS->SetElement(2, 1, newResliceMatrix->GetElement(2, 1));
currentSliceToRAS->SetElement(2, 2, newResliceMatrix->GetElement(2, 2));
currentSliceToRAS->SetElement(2, 3, registrationMatrix->GetElement(2, 3));
d->redViewer->UpdateMatrices();

The axial slice lines up perfect with the model in the beginning, but when I start to rotate, the slice does not rotate around the Y axis of the model.  Any help would be greatly appreciated.  Thanks!

Despite compositing matrices is a really simple operation (you just have to get the order of the matrices right and invert them as needed), you may easily spend a couple of days figuring out the correct combination.

We’ve found that a very good way of getting the correct solution quickly is following these steps:

  1. Define each coordinate system: what is the unit (mm, pixel, …), where is the origin, what are the coordinate system axis directions. It also helps if you draw a sketch of the origin position and axis directions relative to physical objects. See an example in Plus toolkit’s user manual.

  2. Name each transformation as a transformation from coordinate system A to B as AToB (you may add Transform or Matrix suffix to make it even more clear that it is a transform). For example, SliceToRAS is a well-defined transformation. newResliceMatrix and registrationMatrix names are not usable because they don’t specify what coordinate systems they are transforming between and in what order.

  3. Create chain of matrices using the following rules:

  • AToC = BToC * AToB
  • AToB = inv(BToA)

Alternatively, in some simple cases when you need to place a slice view to a based on a position and a normal vector, you may also find vtkMRMLSliceNode::SetSliceToRASByNTP method useful. See how it is used for rotating slice views in ValveView module.

For real-time positioning of a slice view using a transform, use VolumeResliceDriver module of SlicerIGT extension.

1 Like

Thanks for the explanation. Turns out it was something extremely simple. Matrix multiplication is not commutative. For my example above I was specifying AToC = AToB * BToC. Changing the order fixed the problem right away! Thanks!

1 Like