I would like to invoke in a script “Jump slices” functionality of Segment Editor. I found jumpSlices(), but have not figured out yet how to invoke it, given Segmentation node and ID of the segment that I need to jump to.
I’ve also added VTK size hints to the header file that makes the method return a Python tuple instead of a raw pointer.
We should use these hints everywhere where we return a double* to make the result more Python-friendly. VTK also has hints for range checks on inputs (to prevent crashes in Python caused by trying to get/set an out of range item in a data set).
Aha! I was in a rush, and glossed over Christian’s code too quickly to realize I could use it easily, since the centroid getter function is static. I can easily solve my jumpSlices() problem with just a few lines, using my existing Slicer binary and extensions. Here’s the recipe in case anyone else needs this too (assumes that the QuantitativeReporting extension is installed!):
@cpinter maybe the jumpSlices() function I referenced in the initial post should reuse Markups logic to jump slices to reduce code redundancy? I didn’t look carefully whether there is anything extra done that requires a custom implementation.
The gist of the jump slices method in Markups logic is just one line of code. The jumpSlices code in the SH plugin also considers in which views the segmentation is visible, while the Markups one does not (and cannot). Other than that the rest of the code that makes that function long is getting the item, the segmentation, and the segment.
Using a custom extension is certainly a solution, but in the long term I would recommend developers to use Slicer core functions if available.
Slicer-4.10 returning a swig pointer (such as _000001bfd4897340_p_void) is a minor inconvenience. You can still access the values using the helper function below (in the nightly version the VTK hint is there so the position is directly returned as a Python tuple).
def getListFromPointer(bufferPtr, scalarType=vtk.VTK_DOUBLE, numberOfElements=3):
"""Convert swig pointer (_..._p_void) to list object"""
bufferArray = vtk.vtkAbstractArray.CreateArray(vtk.VTK_DOUBLE)
bufferArray.SetVoidArray(bufferPtr, numberOfElements, True)
buffer = [bufferArray.GetValue(i) for i in range(numberOfElements)]
Yes, but if an experienced Slicer engineer, such as @che85, made the decision to re-implement this functionality for one reason or another, then maybe there’s a need to revisit something. What are the chances that a beginner developer will figure this out.
Andras, can you share your thought process? I guess it is a minor inconvenience when you know what is going on. I just didn’t want my previous post to make it look as if it was a minor inconvenience for me. I simply had no clue what it means when I saw that p_void.
Do you mean how did I know how to access the buffer content? I remembered that someone asked this already on Slicer or VTK mailing list and there was a positive answer, so I knew that it was possible. I google searched for VTK p_void and found a test in VTK source code that showed how to get the values.
@che85 implemented this first, we added it to Slicer core later. I checked how he implemented and probably even used some code from his implementation.
I agree that it is not easy. I would say a good assumption is that anything that is not super-specific to a project has come up already in some other projects, so there is at least something to start from and the task is to find it. If a Google web search and local search in all Slicer’s source code (including VTK, CTK, ITK, …) does not bring up anything then I would recommend to ask on the Slicer forum.
It would be nice to proactively document things, but it would be a lot of work, not very exciting kind, and would be hard to know what topics we should focus on. In contrast, answering questions on the forum helps people immediately and it also generates an indexed, searchable knowledge base to supplement other forms of documentations. Not perfect system, but considering that we have limited amount of time, it is reasonable.
Thanks Andras, this is helpful, and I agree with you.
@che85 has been through the experience of implementing things that he thought are of general interest, and abstracted them out into Slicer Development Toolbox. I thought it might be nice to consider this as a central place for the functionality of general interest, which is either not ready for the core, or there are no resources to move it to the core.
I also like the approach of testing concepts in a single extension(not in a shared utility extension) then send a pull request to Slicer core. This allows reviewing the code earlier and dealing with smaller chunks of code at once. The disadvantage is that the API is not widely tested, so the API often has to be tuned later to support all important use cases.