Cell Locator API
Markups, Models, and Annotations
Each annotation in the scene has a markup associated with it, and also a translucent 3d
model to represent the thickness of that annotation. So for each element in the scene,
we need to manage a vtkMRMLMarkupsNode
and a vtkMRMLModelNode
. The
Annotation
class in Python does this and handles serialization to JSON.
Annotation
is an abstract class, currently with two concrete implementations:
FiducialAnnotation
and ClosedCurveAnnotation
.
FiducialAnnotation
consists only of points with no thickness. Since this behavior is
provided by vtkMRMLMarkupsFiducialNode
; so the annotation does not need to update a
model.
ClosedCurveAnnotation
does have thickness. Its markup is a
vtkMRMLMarkupsClosedCurveNode
, and a model is generated from this markup using
vtkSlicerSplinesLogic::CreateModelFromContour
(see here)
Creating Annotation Types
Below is a template for creating a new type of Annotation. Keep in mind that
Annotation
does not create a model, so if you need one (or any other nodes) for the
new type, you must create those in NewAnnotation.__init__
.
class NewAnnotation(Annotation):
DisplayName = 'Sample' # default name for this annotation type
MarkupType = 'vtkMRMLMarkupsFiducialNode' # markup type managed by this annotation type
def __init__(self, markup=None):
# set any type-specific attributes, models, etc
super().__init__(markup=markup)
# do any DisplayNode customizations
def clear(self):
# do any cleanup of type-specific attributes
def update(self):
# update any type-specific attributes; models, etc
def metadata(self):
# convert type-specific attributes to dict for serialization
def setMetadata(self, data):
# set any type-specific attributes from dict for deserialization
Annotation.update
is invoked each time the markup changes, so we can implement it to
re-generate a model. Any other nodes or data that need to be synchronized with the
markup can be updated here.
Serialization
Annotations are serialized to JSON using Annotation.toDict
. The markup is converted
to JSON by Slicer (see here). Any annotation-specific metadata (thickness, etc) is
included using Annotation.getMetdata
.
Deserialization
Annotations are deserialized using Annotation.fromDict
. The specific annotation
type is determined using the markup type, and the annotation type’s MarkupType
class attribute.
class PlaneAnnotation(Annotation):
MarkupType = 'vtkMRMLMarkupsPlaneNode'
For example, if the above class is defined and a vtkMRMLMarkupsPlaneNode
is stored
in the JSON, then the resulting annotation will be an instance of PlaneAnnotation
.
The JSON contents will then be sent to PlaneAnnotation.setMetadata
so that any
attributes specific to PlaneAnnotation
may be deserialized.