I had a problem, back then, with the rotation. I had a cylinder, C1, in space, with its rotation and another one C2, placed at the origin (0,0,0). I wanted to move and rotate C2 like C1, so C2 overlaps C1. I did it with euler angles using the transformation matrix 4x4.
Now i have another problem. I have a model of a brain and many models of cylinders that represent electrodes to capture brain activities and i wanted to detect if a specific cylinder is outside or inside the brain and color it accordingly. I tried with vtkCollisionDetectionFilter()
and had my problems and i already made a post about it here, but then i found another class vtkSelectEnclosedPoints()
that works better for my case, because giving an input data, a surface data, then i just use the function IsInside()
to check if the input data is inside the surface data. But weird enough, the result was all wrong.
Turns out, the transformation matrix is the one that was giving the errors.
I rewrote the code without the transformation matrix, so both brain and cylinder have the same cartesian system, and the vtkSelectEnclosedPoints()
works fine. Turns out, that if i rotate with the euler angles, so using the transformation matrix, the brain and the cylinder have different cartesiam system. So for example, the position in space (0,0,0) for the brain is different for the cylinder, because they are refering to different cartesian system.
What can i do?
### Create a vtk cylinder
cylinderSource = vtk.vtkCylinderSource()
cylinderSource.SetCenter(0,0,0)
cylinderSource.SetHeight(list(models.values())[0][1])
cylinderSource.SetRadius(list(models.values())[0][2])
cylinderSource.SetResolution(100)
cylinderSource.Update()
### Create a model of the cylinder to add to the scene
cylindermodel = slicer.vtkMRMLModelNode()
cylindermodel.SetName(name + "_direction")
cylindermodel.SetAndObservePolyData(cylinderSource.GetOutput())
#Create a Transform node for the model to copy the rotation
cylinderTS = slicer.vtkMRMLTransformNode()
##compute the rotation
#Given the vector (p1,p3) i move it to the origin
vorigin = np.subtract(p1,p3)
#compute rotation matrix
R = self.rotMat(vorigin)
#from 3x3 matrix i transformit in a 4x4 matrix
matrix4 = self.mat3To4(R, float(points[p]), float(points[p + 1]), float(points[p + 2]))
#from 4x4 matrix, generate vtkmatrix4x4 object
rMatrix = self.mat4x4Gen(matrix4)
#add the rotation to the model
cylinderTS.SetAndObserveMatrixTransformToParent(rMatrix)
cylindermodelDisplay = slicer.vtkMRMLModelDisplayNode()
cylindermodelDisplay.SetSliceIntersectionVisibility(True) # Hide in slice view
cylindermodelDisplay.SetVisibility(True) # Show in 3D view
cylindermodelDisplay.SetColor(1, 0, 0)
cylindermodelDisplay.SetLineWidth(2)
cylindermodelDisplay.SetOpacity(0.5)
slicer.mrmlScene.AddNode(cylindermodelDisplay)
cylindermodel.SetAndObserveDisplayNodeID(cylindermodelDisplay.GetID())
slicer.mrmlScene.AddNode(cylinderTS)
cylindermodel.SetAndObserveTransformNodeID(cylinderTS.GetID())
slicer.mrmlScene.AddNode(cylindermodel)
# Check if electrodes are inside or outside the brain
for j in range(0, len(listBrain)):
select = vtk.vtkSelectEnclosedPoints()
select.SetInputData(cylindermodel.GetPolyData())
select.SetSurfaceData(listBrain[j])
select.SetTolerance(.00001)
select.Update()
if select.IsInsideSurface([float(points[p]), float(points[p + 1]), float(points[p + 2])]):
cylindermodelDisplay.SetColor(1, 1, 1)
fidNode.SetNthFiducialLabel(a, name + str((p / 3) + 1)+"#")
del select
def mat4x4Gen(self, m):
rMatrix = vtk.vtkMatrix4x4()
for x in range(4):
for y in range(4):
rMatrix.SetElement(x, y, m[x][y])
return rMatrix
def mat3To4(self, m,x,y,z):
b = np.array([[0, 0, 0]])
c = np.concatenate((m, b), axis=0)
d = np.array([[x, y, z, 1]])
return np.concatenate((c, d.T), axis=1)
def rotMat(self, vec2):
""" Find the rotation matrix that aligns vec1 to vec2
:param vec1: A 3d "source" vector
:param vec2: A 3d "destination" vector
:return mat: A transform matrix (3x3) which when applied to vec1, aligns it with vec2.
"""
vec1 = [0,1,0]
a, b = (vec1 / np.linalg.norm(vec1)).reshape(3), (vec2 / np.linalg.norm(vec2)).reshape(3)
v = np.cross(a, b)
c = np.dot(a, b)
s = np.linalg.norm(v)
kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rotation_matrix = np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2))
return rotation_matrix