# Rotate reformat slice view (in plane)

**URL:** <https://discourse.slicer.org/t/rotate-reformat-slice-view-in-plane/8127>\
**Category:** Development\
**Created:** [August 21, 2019, 7:07pm UTC](https://discourse.slicer.org/t/rotate-reformat-slice-view-in-plane/8127 "2019-08-21T19:07:45Z")\
**Posts on this page:** 1\
**Showing post:** 6

<div class="post-metadata">

**Author:** ![mikebind](https://avatars.discourse-cdn.com/v4/letter/m/71e660/32.png) [@mikebind](https://discourse.slicer.org/u/mikebind)\
**Post date:** [August 23, 2019, 11:02pm UTC](https://discourse.slicer.org/t/rotate-reformat-slice-view-in-plane/8127/6 "2019-08-23T23:02:40Z")

</div>

Here is what ended up working for me:

`def setSlicePoseFromSliceNormalAndPosition(sliceNode, sliceNormal, slicePosition, offsetOrCenter='offset'):`

> ```
> """
> Set slice pose from the provided plane normal and position. The most similar canonical view (sagittal, coronal, 
> or axial) is determined by the direction of the sliceNormal. For example, if the largest component of the 
> sliceNormal is in the superior direction (or negative superior direction), then the most similar canonical view
> is the axial view. Care is taken to not allow misleading views, such as an axial-appearing view which has the 
> patient's right on the right hand side (reversed from the standard axial view). If the supplied normal would 
> naturally lead to such a misleading view, it is negated. 
> :param offsetOrCenter should be either 'offset' or 'center', and is used to determine whether the view should 
> be shifed to the given slicePosition by jumping by offsetting or by centering (using sliceNode.JumpSlicesByOffsetting
> or sliceNode.JumpSlicesByCentering, respectively).   
> """
> 
> ```

```
# Ensure sliceNormal is numpy array
sliceNormal = np.array(sliceNormal)

# Find largest and smallest components of sliceNormal
largestComponentAxis = np.argmax(np.abs(sliceNormal)) # used to determine most similar view
smallestComponentAxis = np.argmin(np.abs(sliceNormal)) # used to decide which of the slice X or Y axes to precisely align

if largestComponentAxis==smallestComponentAxis:
    raise ValueError('Largest and smallest slice normal components are the same!!')

viewLookup = {0: 'sagittal',
         1: 'coronal',
         2: 'axial'}

mostSimilarView = viewLookup[largestComponentAxis]
#print mostSimilarView
    
# In order to make the adjusted view as similar as possible to a standard view, it may be necessary to use
# the negation of the given slice normal rather than the given slice normal.  

# The cross product relationships among the 3 axes are
# Y = NxX, X = YxN, N = XxY (where x means vector cross product here, recall that order matters)

# In each of the mostSimilarView cases which follow, we 
# 1) use the sign of the largest component to determine whether the sliceNormal needs to be negated 
# to more closely conform to the corresponding canonical view, 
# 2) use the smallest component to determine which of the remaining axes is closer to lying in the new slice view 
# plane. The smaller the component in the direction of the sliceNormal, the larger the component must be in 
# the orthogonal plane.
# 3) set the direction of the slice X axis so that the projection of the most in-plane of the R,A, or S axes 
# points precisely in the correct direction. If it is the new Y axis which is to be aligned, the X axis direction
# is determined by finding the cross product of the Y axis with the sliceNormal. 
# 
# Note that we can handle the normalization to unit vectors later, so if we want the slice Y axis to align as closely
# as possible to the Superior axis, we can assign sliceAxisY to be [0,0,1] for now, even if the sliceNormal guarantees
# that the vector [0,0,1] is not in the slice plane. After the cross products and normalization, the sliceAxisY

if mostSimilarView=='sagittal':
    # Canonical view is image up is superior, image right is posterior, and patient right points out of screen
    if sliceNormal[largestComponentAxis]>0:
        sliceNormal = -sliceNormal # invert the normal if it would lead the Right axis to point into the screen
    if smallestComponentAxis==2:
        # if superior is closest to in-plane, say that up should be superior
        sliceAxisY = [0,0,1]
        sliceAxisX = np.cross(sliceAxisY,sliceNormal)
        #print 'up should be superior'
    elif smallestComponentAxis==1:
        # if right is closest to in-plane, say that right should be posterior
        sliceAxisX = [0,-1,0]
        #print 'right should be posterior'
    
elif mostSimilarView=='coronal':
    # Canonical view is image up is superior, image right is patient left, and anterior points into the screen
    if sliceNormal[largestComponentAxis]<0:
        sliceNormal = -sliceNormal # invert the normal if it would lead the anterior axis to point out of the screen        
    if smallestComponentAxis==2:
        # if superior is closest to in-plane, say that up should be superior
        sliceAxisY = [0,0,1]
        sliceAxisX = np.cross(sliceAxisY,sliceNormal)
        #print('up should be superior')
    elif smallestComponentAxis==0:
        # if right is closest to in-plane, say that right should be left
        sliceAxisX = [-1,0,0]
        print 'right should be patient left'
    
elif mostSimilarView=='axial':
    # Canonical view is image up is anterior and image right is left
    if sliceNormal[largestComponentAxis]>0:
        sliceNormal=-sliceNormal # invert the normal if it would lead the Superior axis to point into the screen        
    if smallestComponentAxis==1:
        # if anterior is closest to in-plane, say that up should be anterior
        sliceAxisY = [0,1,0]
        sliceAxisX = np.cross(sliceAxisY,sliceNormal)
        print 'up should be anterior'+' sliceAxisX='+str(sliceAxisX)
    elif smallestComponentAxis==0:
        # if right is closest to in-plane, say that right should be left
        sliceAxisX = [-1,0,0]
        print 'right should be patient left'+' sliceAxisX='+str(sliceAxisX)
    
else:
    # Should throw error here
    raise ValueError('mostSimilarView must be axial, coronal, or sagittal, but is "'+mostSimilarView+'"')

vtkSliceToRAS = sliceNode.GetSliceToRAS()
oldPosition = [vtkSliceToRAS.GetElement(0,3),
               vtkSliceToRAS.GetElement(1,3),
               vtkSliceToRAS.GetElement(2,3)]

# In the new SliceToRAS matrix, sliceAxisX should be the first column, sliceAxisY should be the second column, 
# and the normal vector should be the third colum (sliceAxisZ). These should all be normalized and orthogonal.

# SetSliceToRASByNTP handles this by 1) normalizing the input N and T vectors (slice normal and sliceAxisX),
# 2) crossing them to generate sliceAxisY, and then 3) crossing the slice normal and sliceAxisY to generate
# an updated version of sliceAxisX which is guaranteed to be orthogonal to both sliceAxisY and the slice normal. 

sliceNormal = np.array(sliceNormal)
magNormal = np.linalg.norm(sliceNormal)
sliceNormal = sliceNormal/magNormal # normalize

sliceAxisX = np.array(sliceAxisX)
magSliceAxisX = np.linalg.norm(sliceAxisX)
sliceAxisX = sliceAxisX/magSliceAxisX

sliceAxisY = np.cross(sliceNormal,sliceAxisX) # Y = NxX (recall that order matters for cross products)
magSliceAxisY = np.linalg.norm(sliceAxisY)
sliceAxisY = sliceAxisY/magSliceAxisY # normalize

sliceAxisX = np.cross(sliceAxisY,sliceNormal) # X = YxN (this order ensures X points in the same general direction as the original X, but is guaranteed to be orthogonal)
magSliceAxisX = np.linalg.norm(sliceAxisX)

# Set the elements of the SliceToRAS matrix
for rowInd in range(3):
    vtkSliceToRAS.SetElement(rowInd,0,sliceAxisX[rowInd])
    vtkSliceToRAS.SetElement(rowInd,1,sliceAxisY[rowInd])
    vtkSliceToRAS.SetElement(rowInd,2,sliceNormal[rowInd])
    if offsetOrCenter.lower()=='center':
        # use the requested position as the slice center position
        vtkSliceToRAS.SetElement(rowInd,3,slicePosition[rowInd])
        

sliceNode.UpdateMatrices() # This applies the changes to the SliceToRAS matrix

if offsetOrCenter.lower()=='offset':
    # keep the original slice center position, but then adjust offset until it contains requested position
    sliceNode.JumpSliceByOffsetting(slicePosition[0],slicePosition[1],slicePosition[2])
elif offsetOrCenter.lower()=='center':
    sliceNode.JumpSliceByCentering(slicePosition[0],slicePosition[1],slicePosition[2]) [/code]

```

---

_[View the full topic](https://discourse.slicer.org/t/rotate-reformat-slice-view-in-plane/8127)._
