I’m not allowed to upload the scene (format isn’t accepted).
Here is the script that I run :
import logging
import os
from math import dist
import vtk
import numpy as np
import slicer, vtk, qt, SampleData
from slicer.ScriptedLoadableModule import *
from slicer.util import *
from vtkmodules.vtkFiltersCore import vtkTubeFilter
from vtkmodules.vtkFiltersSources import vtkLineSource
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
from vtk.util.numpy_support import vtk_to_numpy
#%%
#
# Needle1
#
class Needle1(ScriptedLoadableModule):
"""Uses ScriptedLoadableModule base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self, parent):
ScriptedLoadableModule.__init__(self, parent)
self.parent.title = "Needle1" # TODO: make this more human readable by adding spaces
self.parent.categories = ["Examples"] # TODO: set categories (folders where the module shows up in the module selector)
self.parent.dependencies = [] # TODO: add here list of module names that this module requires
self.parent.contributors = ["Caroline Essert (University of Strasbourg)"] # TODO: replace with "Firstname Lastname (Organization)"
# TODO: update with short description of the module and a link to online module documentation
self.parent.helpText = """
This is an example of scripted loadable module bundled in an extension.
See more information in <a href="https://github.com/organization/projectname#Needle1">module documentation</a>.
"""
# TODO: replace with organization, grant and thanks
self.parent.acknowledgementText = """
This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc., Andras Lasso, PerkLab,
and Steve Pieper, Isomics, Inc. and was partially funded by NIH grant 3P41RR013218-12S1.
"""
#%%
#
# Needle1Widget
#
class Needle1Widget(ScriptedLoadableModuleWidget, VTKObservationMixin):
"""Uses ScriptedLoadableModuleWidget base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self, parent=None):
"""
Called when the user opens the module the first time and the widget is initialized.
"""
ScriptedLoadableModuleWidget.__init__(self, parent)
VTKObservationMixin.__init__(self) # needed for parameter node observation
# store logic in a member variable
self.logic = Needle1Logic()
def setup(self):
"""
Called when the user opens the module the first time and the widget is initialized.
"""
# initialisation that needs to be here - don't remove
ScriptedLoadableModuleWidget.setup(self)
# Init button
InitButton = qt.QPushButton("Init")
self.layout.addWidget(InitButton)
InitButton.connect('clicked(bool)', self.onInitButtonClicked)
# Create Cylinder button
CreateCyl = qt.QPushButton("Create Cylinder")
self.layout.addWidget(CreateCyl)
CreateCyl.connect('clicked(bool)', self.onCreateCylClicked)
# Place Electrode button
myButton = qt.QPushButton("Place Electrode")
self.layout.addWidget(myButton)
myButton.connect('clicked(bool)', self.onPlaceElectrodeButtonClicked)
# Compute Distance button
myButton = qt.QPushButton("Compute Distance")
self.layout.addWidget(myButton)
myButton.connect('clicked(bool)', self.onComputeDistanceButtonClicked)
# Create Cylinder button callback function
def onCreateCylClicked(self):
# call logic function to print position of the first fiducial (requires a fiducial to be added beforehand to work properly)
self.mySnode = self.logic.myCreateCylinder()
def onPlaceElectrodeButtonClicked(self):
self.logic.myPlacingfct()
def onInitButtonClicked(self):
self.logic.myInit()
def onComputeDistanceButtonClicked(self):
self.logic.myDistance()
#%%
#
# Needle1Logic
#
class Needle1Logic(ScriptedLoadableModuleLogic):
"""This class should implement all the actual
computation done by your module. The interface
should be such that other python code can import
this class and make use of the functionality without
requiring an instance of the Widget.
Uses ScriptedLoadableModuleLogic base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self):
"""
Called when the logic class is instantiated. Can be used for initializing member variables.
"""
ScriptedLoadableModuleLogic.__init__(self)
print('in init logic')
#myP1 = slicer.modules.markups.logic().AddControlPoint(0, 0, 0)
#myP2 = slicer.modules.markups.logic().AddControlPoint(150.0, 0, 0)
try:
f = getNode('F')
obsTag=f.AddObserver(slicer.vtkMRMLMarkupsNode.PointModifiedEvent, self.modifyMyCylinder)
print('Observer instantiated')
except slicer.util.MRMLNodeNotFoundException:
print("Please create a fiducial first, no observer yet")
def myInit(self):
try:
f = getNode('F')
obsTag=f.AddObserver(slicer.vtkMRMLMarkupsNode.PointModifiedEvent, self.modifyMyCylinder)
print('Observer instantiated')
except slicer.util.MRMLNodeNotFoundException:
print("Please create a fiducial first, no observer yet")
def myCreateCylinder(self, caller=None, event=None):
#je dois gerer la creation des points si ils exisent pas encore, sinon creer sans cesse de nouveaux doublets de points
try :
f = getNode('F')
print('f found in try')
#print(dir(self))
#update the position of the cylinder
self.modifyMyCylinder()
print(self.myLine)
print(self.myCylinder)
except slicer.util.MRMLNodeNotFoundException:
print("I'll create 2 fiducials first")
myP1 = slicer.modules.markups.logic().AddControlPoint(0, 0, 0)
myP2 = slicer.modules.markups.logic().AddControlPoint(150.0, 0, 0)
f = getNode('F')
# initilize a position
pos=[0,0,0]
# get the first fiducial's position in pos (fiducial of index=0)
f.GetNthFiducialPosition(0,pos)
#print(pos)
posF2=[0,0,0]
f.GetNthFiducialPosition(1,posF2)
#print(posF2)
lineSource = vtkLineSource()
lineSource.SetPoint1(pos)
lineSource.SetPoint2(posF2)
lineMapper = vtkPolyDataMapper()
lineMapper.SetInputConnection(lineSource.GetOutputPort())
lineActor = vtkActor()
lineActor.SetMapper(lineMapper)
# Create tube filter
tubeFilter = vtkTubeFilter()
tubeFilter.SetInputConnection(lineSource.GetOutputPort())
tubeFilter.SetRadius(1)
tubeFilter.SetNumberOfSides(50)
tubeFilter.Update()
self.myLine = lineSource
self.myCylinder = tubeFilter
sNode=slicer.modules.models.logic().AddModel(tubeFilter.GetOutputPort())
sNode.SetAndObservePolyData(tubeFilter.GetOutput())
sDisplayNode=sNode.GetDisplayNode()
return sNode
def myPlacingfct(self):
right_snt = slicer.mrmlScene.GetFirstNodeByName('63_stn_right.vtk')
pointCoordinates = slicer.util.arrayFromModelPoints(right_snt)
pd = right_snt.GetPolyData().GetPoints().GetData() #right_snt.GetPolyData().GetCenter()
centroid_right_snt = np.average(vtk_to_numpy(pd), axis=0)
f = getNode('F')
posF2 = [20,20,20]
f.SetNthFiducialPositionFromArray(0,centroid_right_snt)
f.GetNthFiducialPosition(1,posF2)
self.myLine.SetPoint1(centroid_right_snt)
self.myLine.SetPoint2(posF2)
self.myLine.Update()
self.myCylinder.Update()
print('Electrode placed in the middle of the right STN')
def modifyMyCylinder(self,caller=None, event=None):
print('Position of one fiducial changed, adjusting the cylinder')
f = getNode('F')
pos=[0,0,0]
f.GetNthFiducialPosition(0,pos)
posF2=[0,0,0]
f.GetNthFiducialPosition(1,posF2)
self.myLine.SetPoint1(pos)
self.myLine.SetPoint2(posF2)
self.myLine.Update()
self.myCylinder.Update()
def myDistance(self,caller=None,event=None):
right_sulci = slicer.mrmlScene.GetFirstNodeByName('63_sulci_right.vtk')
left_sulci = slicer.mrmlScene.GetFirstNodeByName('63_sulci_left.vtk')
fourth_ventricule = slicer.mrmlScene.GetFirstNodeByName('63_fourth_ventricle.vtk')
third_ventricule = slicer.mrmlScene.GetFirstNodeByName('63_third_ventricle.vtk')
lat_left_ventricule = slicer.mrmlScene.GetFirstNodeByName('63_lateral_ventricle_left.vtk')
lat_right_ventricule = slicer.mrmlScene.GetFirstNodeByName('63_lateral_ventricle_right.vtk')
tab_sulci = [right_sulci,left_sulci]
tab_ventricule = [fourth_ventricule,third_ventricule,lat_left_ventricule,lat_right_ventricule]
needle = self.myCylinder.GetOutputPort()
print(type(self.myCylinder.GetOutputPort()))
print(type(lat_left_ventricule.GetPolyDataConnection()))
distanceFilter = vtk.vtkDistancePolyDataFilter()
distanceFilter.SetInputConnection(0, needle)
distanceFilter.SetInputConnection(1, lat_left_ventricule.GetPolyDataConnection()) #self.myCylinder.GetOutputPort()
#distanceFilter.SignedDistanceOff()
distanceFilter.Update()
print(type(distanceFilter))
#print(distanceFilter.GetOutput().GetPointData().GetScalars().GetRange()[0])
""" for vec in tab_sulci:
print(type(vec))
print('////////////////////\n')
for vec in tab_ventricule:
print(type(vec))
print('////////////////////\n')
"""
"""
print('Distance to ventricules : ')
"""
#%%
#
# Needle1Test
#
class Needle1Test(ScriptedLoadableModuleTest):
"""
This is the test case for your scripted module.
Uses ScriptedLoadableModuleTest base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def setUp(self):
""" Do whatever is needed to reset the state - typically a scene clear will be enough.
"""
# open the MRBrainTumor1 sample dataset
sampleDataLogic = SampleData.SampleDataLogic()
masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1()
def runTest(self):
"""Run as few or as many tests as needed here.
"""
self.setUp()
self.test_Needle11()
def test_Needle11(self):
""" Ideally you should have several levels of tests. At the lowest level
tests should exercise the functionality of the logic with different inputs
(both valid and invalid). At higher levels your tests should emulate the
way the user would interact with your code and confirm that it still works
the way you intended.
One of the most important features of the tests is that it should alert other
developers when their changes will have an impact on the behavior of your
module. For example, if a developer removes a feature that you depend on,
your test should break so they know that the feature is needed.
"""
# quick message box to inform that the test is starting
self.delayDisplay("Starting the test")
# create node to store fiducials
markupsNodeID = slicer.modules.markups.logic().AddNewFiducialNode()
markupsNode = getNode(markupsNodeID)
markupsNode.SetName("F")
# add one fiducial
markupsNode.AddFiducial(6.4, 35.1, 0.7)
# get the logic
logic = Needle1Logic()
# call function printPosF1 to test it on the previously added fiducial
#logic.printPosF1()
# quick message box to inform that the test has successfully ended
self.delayDisplay('Test passed')
As an exemple, the scene looks like this :
My goal is to compute the distance between the cylinder ‘Model’ created with the function ‘myCreateCylinder’ and one of the ventricule.