Source code for anatomist.base

# -*- coding: utf-8 -*-
#  This software and supporting documentation are distributed by
#      Institut Federatif de Recherche 49
#      CEA/NeuroSpin, Batiment 145,
#      91191 Gif-sur-Yvette cedex
#      France
#
# This software is governed by the CeCILL license version 2 under
# French law and abiding by the rules of distribution of free software.
# You can  use, modify and/or redistribute the software under the
# terms of the CeCILL license version 2 as circulated by CEA, CNRS
# and INRIA at the following URL "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license version 2 and that you accept its terms.

"""
General interface of pyanatomist API. It describes classes and methods that are shared by all implementations: the set of Anatomist features available throught this API.

Several implementations exist depending on the mean of driving Anatomist (Sip bindings C++/Python or commands via socket).
"""

from __future__ import print_function

from __future__ import absolute_import
from soma.notification import ObservableNotifier
from soma.singleton import Singleton
from soma.functiontools import partial
import operator
import string
import threading
import collections
import sys
import six


def isSequenceType(item):
    if isinstance(item, collections.Sequence):
        return True
    if hasattr(item, 'isArray'):
        # aims Object API
        return item.isArray()
    if isMappingType(item):
        return False
    methods = ['__getitem__', '__contains__', '__iter__', '__len__']
    # should also include: count, index but pyaims sequences do not have them
    for m in methods:
        if not hasattr(item, m):
            return False
    return True


def isMappingType(item):
    if isinstance(item, collections.Mapping):
        return True
    if hasattr(item, 'isDictionary'):
        # aims Object API
        return item.isDictionary()
    methods = ['get', 'items', 'keys', 'values', '__getitem__', '__iter__',
               '__contains__', '__len__']
    if six.PY2:
        methods.append('iteritems')
    for m in methods:
        if not hasattr(item, m):
            return False
    return True


[docs]class Anatomist(Singleton): """ Interface to communicate with an Anatomist Application. This class is virtual, some methods are not implemented. It is the base class of Anatomist classes in each implementation. This class is a Singleton, so there is only one global instance of this class. The first time the constructor is called, an instance is created. Each next time, the same instance is returned. It is also possible to ask for anatomist instance without creating an instance if it does not exit. To do this, use the constructor with create=False as parameter : >>> a=anatomist.Anatomist(create=False) will return the current instance or None if no instance exists. This class can notify anatomist events. To call a function when an event occurs, add a listener to one of Anatomist's notifiers. For example: >>> anatomist.onLoadNotifier.add(listener) listener must be a callback function that accepts two parameters : the event name (string) and a dictionary of parameters describing the event. Attributes ---------- onLoadNotifier: :class:`soma.notification.ObservableNotifier` Notifies object loading. Event parameters: ``{'filename': string, 'object': AObject, 'type': string}`` onDeleteNotifier: :class:`soma.notification.ObservableNotifier` Notifies object deletion. Event parameters: ``{'object': AObject}`` onFusionNotifier: :class:`soma.notification.ObservableNotifier` Notifies objects fusion. Event parameters: ``{'children': list of AObject, 'method': string, 'object': AObject, 'type': string}`` onCreateWindowNotifier: :class:`soma.notification.ObservableNotifier` Notifies window creation. Event parameters: ``{'type': string, 'window': AWindow }`` onCloseWindowNotifier: :class:`soma.notification.ObservableNotifier` Notifies window closing. Event parameters: ``{'window': AWindow}`` onAddObjectNotifier: :class:`soma.notification.ObservableNotifier` Notifies object adding in window. Event parameters: ``{'object': AObject, 'window': AWindow}`` onRemoveObjectNotifier: :class:`soma.notification.ObservableNotifier` Notifies object removing from window. Event parameters: ``{'object': AObject, 'window': AWindow}`` onCursorNotifier: :class:`soma.notification.ObservableNotifier` Notifies cursor position change. Event parameters: ``{'position': float vector size 4, 'window': AWindow}`` onExitNotifier: :class:`soma.notification.ObservableNotifier` Notifies that Anatomist application exits. centralRef: :class:`Referential` Anatomist central referential (talairach acpc ref) mniTemplateRef: :class:`Referential` Template mni referential (used by spm) These two referentials and transformation between them are always loaded in anatomist. defaultRefType: str Reference type taken by default on anatomist objects. Strong means that objects or windows cannot be deleted while a reference exist on it. lock: :func:`threading.RLock` Enable to take a lock on anatomist singleton instance """ defaultRefType = "Strong" lock = threading.RLock() def __new__(cls, *args, **kwargs): '''If the keyword arg create is set to False, then a new instance is not created even if the singleton has not been instantiated yet. ''' instance = None create = kwargs.get('create', True) if '_singleton_instance' not in cls.__dict__: if create: instance = super(Anatomist, cls).__new__(cls, *args, **kwargs) else: instance = cls._singleton_instance return instance def __singleton_init__(self, *args, **kwargs): super(Anatomist, self).__singleton_init__() self.onLoadNotifier = ObservableNotifier() # enable listening of event only when the notifier has at least one # listener. self.onLoadNotifier.onAddFirstListener.add( partial(self.enableListening, "LoadObject", self.onLoadNotifier)) self.onLoadNotifier.onRemoveLastListener.add( partial(self.disableListening, "LoadObject")) self.onDeleteNotifier = ObservableNotifier() self.onDeleteNotifier.onAddFirstListener.add( partial(self.enableListening, "DeleteObject", self.onDeleteNotifier)) self.onDeleteNotifier.onRemoveLastListener.add( partial(self.disableListening, "DeleteObject")) self.onFusionNotifier = ObservableNotifier() self.onFusionNotifier.onAddFirstListener.add( partial(self.enableListening, "FusionObjects", self.onFusionNotifier)) self.onFusionNotifier.onRemoveLastListener.add( partial(self.disableListening, "FusionObjects")) self.onCreateWindowNotifier = ObservableNotifier() self.onCreateWindowNotifier.onAddFirstListener.add( partial(self.enableListening, "CreateWindow", self.onCreateWindowNotifier)) self.onCreateWindowNotifier.onRemoveLastListener.add( partial(self.disableListening, "CreateWindow")) self.onCloseWindowNotifier = ObservableNotifier() self.onCloseWindowNotifier.onAddFirstListener.add( partial(self.enableListening, "CloseWindow", self.onCloseWindowNotifier)) self.onCloseWindowNotifier.onRemoveLastListener.add( partial(self.disableListening, "CloseWindow")) self.onAddObjectNotifier = ObservableNotifier() self.onAddObjectNotifier.onAddFirstListener.add( partial(self.enableListening, "AddObject", self.onAddObjectNotifier)) self.onAddObjectNotifier.onRemoveLastListener.add( partial(self.disableListening, "AddObject")) self.onRemoveObjectNotifier = ObservableNotifier() self.onRemoveObjectNotifier.onAddFirstListener.add( partial(self.enableListening, "RemoveObject", self.onRemoveObjectNotifier)) self.onRemoveObjectNotifier.onRemoveLastListener.add( partial(self.disableListening, "RemoveObject")) self.onCursorNotifier = ObservableNotifier() self.onCursorNotifier.onAddFirstListener.add( partial(self.enableListening, "LinkedCursor", self.onCursorNotifier)) self.onCursorNotifier.onRemoveLastListener.add( partial(self.disableListening, "LinkedCursor")) self.onExitNotifier = ObservableNotifier() self.onExitNotifier.onAddFirstListener.add( partial(self.enableListening, "Exit", self.onExitNotifier)) self.onExitNotifier.onRemoveLastListener.add( partial(self.disableListening, "Exit"))
[docs] def enableListening(self, event, notifier): """ Set listening of this event on. So when the event occurs, the notifier's notify method is called. This method is automatically called when the first listener is added to a notifier. That is to say that notifiers are activated only if they have registered listeners. Parameters ---------- event: str Name of the event to listen notifier: soma.notification.Notifier The notifier whose notify method must be called when this event occurs """ pass
[docs] def disableListening(self, event): """ Set listening of this event off. Parameters ---------- event: str Name of the event to disable. """ pass
# objects creation
[docs] def createWindowsBlock(self, nbCols=None, nbRows=None): """ Creates a window containing other windows. Parameters ---------- nbCols: int Number of columns of the windows block nbRows: int Number of rows of the windows block (exclusive with nbCols) Returns ------- block: AWindowsBlock A window which can contain several :class:`AWindow` """ pass
[docs] def createWindow(self, wintype, geometry=None, block=None, no_decoration=None, options=None): """ Creates a new window and opens it. Parameters ---------- wintype: str Type of window to open (``"Axial"``, ``"Sagittal"``, ``"Coronal"``, ``"3D"``, ``"Browser"``, ``"Profile"``, ...) geometry: int vector Position on screen and size of the new window (x, y, w, h) block: AWindowsBlock A block in which the new window must be added no_decoration: bool Indicates if decorations (menus, buttons) can be painted around the view. options: dict Internal advanced options. Returns ------- window: AWindow The newly created window """ pass
[docs] def loadObject(self, filename, objectName=None, restrict_object_types=None, forceReload=True, duplicate=False, hidden=False): """ Loads an object from a file (volume, mesh, graph, texture...) Parameters ---------- filename: str The file containing object data objectName: str Object name restrict_object_types: dict object -> accpepted types list. Ex: ``{'Volume' : ['S16', 'FLOAT']}`` forceReload: bool If *True* the object will be loaded even if it is already loaded in Anatomist. Otherwise, the already loaded one is returned. duplicate: bool If the object already exists, duplicate it. The original and the copy will share the same data but not display parameters as palette. If the object is not loaded yet, load it hidden and duplicate it (unable to keep the original object with default display parameters). hidden: bool a hidden object does not appear in Anatomist main control window. Returns ------- object: AObject The loaded object """ pass
[docs] def duplicateObject(self, source, shallowCopy=True): """ Creates a copy of source object. Parameters ---------- source: AObject The object to copy. Returns ------- object: AObject The copy """ pass
[docs] def createGraph(self, object, name=None, syntax=None, filename=None): """ Creates a graph associated to an object (volume for example). This object initializes the graph dimensions (voxel size, extrema). Parameters ---------- object: AObject The new graph is based on this object name: str Graph name. default is ``'RoiArg'``. syntax: str Graph syntactic attribute. default is ``'RoiArg'``. filename: str Filename used for saving. Default is None. Returns ------- graph: AGraph The new graph object """ pass
[docs] def loadCursor(self, filename): """ Loads a cursor for 3D windows from a file. Parameters ---------- filename: str The file containing object data Returns ------- cursor: AObject The loaded object """ pass
[docs] def fusionObjects(self, objects, method=None, ask_order=False): """ Creates a fusionned multi object that contains all given objects. Parameters ---------- objects: list of :class:`AObject` List of objects that must be fusionned method: str Method to apply for the fusion (``'Fusion2DMethod'``...) ask_order: bool If *True*, asks user in what order the fusion must be processed. Returns ------- object: AObject The newly created fusion object. """ pass
[docs] def getFusionInfo(self, objects=None): """ Gets information about fusion methods. If objects is not specified, the global list of all fusion methods is returned. Otherwise the allowed fusions for those specific objects is returned. Returns ------- info: dict Fusion methods """ pass
[docs] def createReferential(self, filename=None): """ This command does not exist in Anatomist because the command AssignReferential can create a new referential if needed. But the way of creating a new referential depends on the connection with Anatomist, so it seems to be better to encapsulate this step on another command. So referentials are treated the same as other objects. (LoadObject -> addAobject | createReferential -> assignReferential) Parameters ---------- filename: str Name of a file (minf file, extension .referential) containing information about the referential: its name and uuid Returns ------- ref: Referential The newly created referential """ pass
[docs] def loadTransformation(self, filename, origin, destination): """ Loads a transformation from a referential to another. The transformation informations are given in a file. Parameters ---------- filename: str File containing transformation information origin: Referential Origin of the transformation destination: Referential Referential after applying transformation Returns ------- trans: Transformation Transformation to apply to convert coordinates from one referent """ pass
[docs] def createTransformation(self, matrix, origin, destination): """ Creates a transformation from a referential to another. The transformation informations are given in a matrix. Parameters ---------- matrix: float vector, size 12 Transformation matrix (4 lines, 3 colons; 1st line: translation, others: rotation) origin: Referential Origin of the transformation destination: Referential Referential after applying transformation Returns ------- trans: Transformation New transformation """ pass
[docs] def createPalette(self, name): """ Creates an empty palette and adds it in the palettes list. Parameters ---------- name: str Name of the new palette Returns ------- palette: APalette The newly created palette """ pass
[docs] def groupObjects(self, objects): """ Creates a multi object containing objects in parameters. Parameters ---------- objects: list of :class:`AObject` Objects to put in a group Returns ------- group: AObject The newly created multi object """ pass
[docs] def linkWindows(self, windows, group=None): """ Links windows in a group. Moving cursor position in a window moves it in all linked windows. By default all windows are in the same group. Parameters ---------- windows: list of :class:`AWindow` The windows to link group: AWindowsGroup Put the windows in this group. If it is *None*, a new group is created. """ if windows != []: windows = self.makeList(windows) self.execute("LinkWindows", windows=windows, group=group) if group is None: group = windows[0].group return group
# # objects access
[docs] def getPalette(self, name): """ Returns ------- palette: APalette The named palette """ pass
# information that can be obtained with GetInfo command
[docs] def getObjects(self): """ Gets all objects referenced in current context. Returns ------- objects: list of :class:`AObject` List of existing objects """ pass
[docs] def importObjects(self, top_level_only=False): """ Gets objects importing those that are not referenced in the current context. Parameters ---------- top_level_only: bool If *True*, imports only top-level objects (that have no parents), else all objects are imported. Returns ------- objects: list of :class:`AObject` List of existing objects """ pass
[docs] def getObject(self, filename): """ Get the object corresponding to this filename if it is currently loaded. Parameters ---------- filename: str Filename of the requested object Returns ------- object: AObject The object if it is loaded, else returns *None*. """ objects = self.getObjects() loadedObject = None for o in objects: if o.filename == filename and not o.copy: loadedObject = o break return loadedObject
[docs] def getWindows(self): """ Gets all windows referenced in current context. Returns ------- windows: list of :class:`AWindow` List of opened windows """ pass
[docs] def importWindows(self): """ Gets all windows importing those that are not referenced in the current context. Returns ------- windows: list of :class:`AWindow` List of opened windows """ pass
[docs] def getReferentials(self): """ Gets all referentials in current context. Returns ------- refs: list of :class:`Referential` List of referentials """ pass
[docs] def importReferentials(self): """ Gets all referentials importing those that are not referenced in the current context. Returns ------- refs: list of :class:`Referential` List of referentials """ pass
[docs] def getTransformations(self): """ Gets all transformations. Returns ------- trans: list of :class:`Transformation` List of transformations """ pass
[docs] def importTransformations(self): """ Gets all transformations importing those that are not referenced in the current context. Returns ------- trans: list of :class:`Transformation` List of transformations """ pass
[docs] def getPalettes(self): """ Returns ------- palettes: list of :class:`APalette` List of palettes. """ pass
[docs] def getSelection(self, group=None): """ Parameters ---------- group: AWindowsGroup Get the selection in this group. If *None*, returns the selection in the default group. Returns ------- objects: list of :class:`AObject` The list of selected objects in the group of windows """ pass
[docs] def getDefaultWindowsGroup(self): ''' Normally returns 0 ''' return self.AWindowsGroup(self, 0)
[docs] def linkCursorLastClickedPosition(self, ref=None): """ Gives the last clicked position of the cursor. Parameters ---------- ref: Referential If given, cursor position value will be in this referential. Else, anatomist central referential is used. Returns ------- position: float vector, size 3 Last position of the cursor """ pass
[docs] def getAimsInfo(self): """ Returns ------- info: str Information about AIMS library. """ pass
[docs] def getCommandsList(self): """ Returns ------- commands: dict List of commands available in Anatomist with their parameters. dict command name -> dict parameter name -> dict attribute -> value (needed, type) """ pass
[docs] def getModulesInfo(self): """ Returns ------- modules: dict List of modules and their description. dict module name -> dict attribute -> value (description) """ pass
[docs] def getVersion(self): """ Returns ------- version: str Anatomist version """ pass
# # objects manipulation
[docs] def showObject(self, object): '''Displays the given object in a new window''' self.execute("ShowObject", object=object)
[docs] def addObjects(self, objects, windows, add_children=False, add_graph_nodes=True, add_graph_relations=False, temporary=False, position=-1): """ Adds objects in windows. The objects and windows must already exist. Parameters ---------- objects: list of :py:class:`AObject` List of objects to add windows: list of :py:class:`AWindow` List of windows in which the objects must be added add_children: bool (optional) if children objects should also be added individually after their parent add_graph_relations: bool (optional) if graph relations should be also be added temporary: bool (optional) temporary object do not affect the view boundaries and camera settings position: int (optional) insert objects as this order number """ self.execute("AddObject", objects=self.makeList(objects), windows=self.makeList(windows), add_children=int(add_children), add_graph_nodes=int(add_graph_nodes), add_graph_relations=int(add_graph_relations), temporary=int(temporary), position=position)
[docs] def removeObjects(self, objects, windows, remove_children=False): """ Removes objects from windows. Parameters ---------- objects: list of :class:`AObject` List of objects to remove windows: list of :class:`AWindow` List of windows from which the objects must be removed """ self.execute("RemoveObject", objects=self.makeList(objects), windows=self.makeList(windows), remove_children=int(remove_children))
[docs] def deleteObjects(self, objects): """ Deletes objects Parameters ---------- objects: list of :class:`AObject` Objects to delete """ objects = self.makeList(objects) for o in objects: o.releaseRef()
# self.execute("DeleteObject", objects=objects)
[docs] def deleteElements(self, elements): """ Deletes objects, windows, referentials, anything that is referenced in anatomist application. Parameters ---------- elements: list of :class:`AItem` Elements to delete """ self.execute("DeleteElement", elements=self.makeList(elements))
[docs] def reloadObjects(self, objects): """ Reload objects already in memory reading their files. """ self.execute("ReloadObject", objects=self.makeList(objects))
[docs] def assignReferential(self, referential, elements): """ Assign a referential to objects and/or windows. The referential must exist. To create a new Referential, execute createReferential, to assign the central referential, first get it with :attr:`Anatomist.centralRef` attribute. Parameters ---------- referential: Referential The referential to assign to objects and/or windows elements: list of :class:`AItem` Objects or windows which referential must be changed. The corresponding command tree contains an attribute central_ref to indicate if the referential to assign is anatomist central ref, because this referential isn't referenced by an id. In the socket implementation, Referential object must have an attribute central_ref, in order to create the command message. In direct impl, it is possible to access directly to the central ref object. """ objects = [] windows = [] # in anatomist command, objects and windows must be passed in two lists for e in self.makeList(elements): if issubclass(e.__class__, Anatomist.AObject): objects.append(e) elif issubclass(e.__class__, Anatomist.AWindow): windows.append(e) self.execute( "AssignReferential", ref_id=referential, objects=objects, windows=windows, central_ref=referential.centralRef)
[docs] def loadReferentialFromHeader(self, objects): """ Extracts referentials / transformations from objects headers when they contain such information, and assign them. Parameters ---------- objects: list of :class:`AObject` Objects which referential information must be loaded """ self.execute( "LoadReferentialFromHeader", objects=self.makeList(objects))
applyBuiltinReferential = loadReferentialFromHeader
[docs] def camera(self, windows, zoom=None, observer_position=None, view_quaternion=None, slice_quaternion=None, force_redraw=False, cursor_position=None, boundingbox_min=None, boundingbox_max=None, slice_orientation=None): """ Sets the point of view, zoom, cursor position for 3D windows. Parameters ---------- windows: list of :class:`AWindow` Windows which options must be changed zoom: float Zoom factor, default is 1 observer_position: float vector, size 3 Camera position view_quaternion: float vector, size 4, normed View rotation slice_quaternion: float vector, size 4, normed Slice plane rotation force_redraw: bool If *True*, refresh printing immediatly, default is *False* cursor_position: float vector Linked cursor position boundingbox_min: float vector Bounding box min values boundingbox_max: float vector Bounding box max values slice_orientation: float vector, size 3 Slice plane orientation, normal to the plane """ if force_redraw: force_redraw = 1 else: force_redraw = 0 self.execute( "Camera", windows=self.makeList(windows), zoom=zoom, observer_position=observer_position, view_quaternion=view_quaternion, slice_quaternion=slice_quaternion, force_redraw=force_redraw, cursor_position=cursor_position, boundingbox_min=boundingbox_min, boundingbox_max=boundingbox_max, slice_orientation=slice_orientation)
[docs] def setWindowsControl(self, windows, control): """ Changes the selected button in windows menu. Parameters ---------- windows: list of :class:`AWindow` Windows to set control on control: str Control to set. Examples of controls: 'PaintControl', 'NodeSelectionControl', 'Default 3D Control', 'Selection 3D', 'Flight Control', 'ObliqueControl', 'TransformationControl', 'CutControl', 'Browser Selection', 'RoiControl'... """ self.execute( "SetControl", windows=self.makeList(windows), control=control)
[docs] def closeWindows(self, windows): """ Closes windows. Parameters ---------- windows: list of :class:`AWindow` Windows to be closed """ windows = self.makeList(windows) for w in windows: w.releaseRef()
# self.execute("CloseWindow", windows=windows)
[docs] def setMaterial(self, objects, material=None, refresh=True, ambient=None, diffuse=None, emission=None, specular=None, shininess=None, lighting=None, smooth_shading=None, polygon_filtering=None, depth_buffer=None, face_culling=None, polygon_mode=None, unlit_color=None, line_width=None, ghost=None, front_face=None, selectable_mode=None, use_shader=None, shader_color_normals=None, normal_is_direction=None): """ Changes objects material properties. Parameters ---------- objects: AObject or list objects to change material on. material: Material Material characteristics, including render properties. The material may be specified as a Material object, or as its various properties (ambient, diffuse, etc.). If both a material parameter and other properties are specified, the material is used as a base, and properties are used to modify it refresh: bool If *True*, force windows refreshing ambient: list RGB[A] vector: float values between 0 and 1. diffuse: list RGB[A] vector: float values between 0 and 1. This parameter corresponds to the "standard" notion of color emission: list RGB[A] vector: float values between 0 and 1. specular: list RGB[A] vector: float values between 0 and 1. shininess: float 0-124 lighting: int enables (1) or disables (0) objects lighting/shading. Setting this value to -1 goes back to the default mode (globally set at the view/scene level). smooth_shading: int (tristate: 0/1/-1) smooth or flat polygons mode polygon_filtering: int (tristate: 0/1/-1) filtering (antialiasing) of lines/polygons depth_buffer: int (tristate: 0/1/-1) enables/disables writing in the Z-buffer. You can disable it if you want to click "through" an object (but it may have strange effects on the rendering) face_culling: int (tristate: 0/1/-1) don't draw polygons seen from the back side. The best is to enable it for transparent objects, and to disable it for "open" (on which both sides may be seen) and opaque meshes. For objects both open and transparent, there is no perfoect setting... polygon_mode: string polygons rendering mode: "normal", "wireframe", "outline" (normal + wireframe), "hiddenface_wireframe" (wireframe with hidden faces), "default" (use the global view settings), "ext_outlined" (thickened external boundaries + normal rendering). unlit_color: RGB[A] vector: float values between 0 and 1. color used for lines when lighting is off. For now it only affects polygons boundaries in "outlined" or "ext_outlined" polygon modes. line_width: float Lines thickness (meshes, segments, wireframe rendering modes). A null or negative value fallsback to default (1 in principle). front_face: string Specifies if the mesh(es) polygons external face is the clockwise or counterclockwise side. Normally in Aims/Anatomist indirect referentials, polygons are in clockwise orientation. Values are "clockwise", "counterclockwise", or "neutral" (the default). selectable_mode: string New in Anatomist 4.5. Replaces the ghost property. **always_selectable**: object is selecatble whatever its opacity. **ghost**: object is not selectable. **selectable_when_opaque**: object is selectable when totally opaque (this is the default in Anatomist). **selectable_when_not_totally_transparent**: object is selectable unless opacity is zero. use_shader: int enable or disable the use of OpenGL shaders for this object. shader_color_normals: int when shaders are enabled, normals can be represented as colors on the object. normal_is_direction: int when shaders are enabled and shader_color_normals is set, normals may be pre-calculates as mesh direction, on a "line" mesh (polygons are lines, not triangles). """ if material is not None: if ambient is None: ambient = material.ambient if diffuse is None: diffuse = material.diffuse if emission is None: emission = material.emission if specular is None: specular = material.specular if shininess is None: shininess = material.shininess if lighting is None: lighting = material.lighting if smooth_shading is None: smooth_shading = material.smooth_shading if polygon_filtering is None: polygon_filtering = material.polygon_filtering if depth_buffer is None: depth_buffer = material.depth_buffer if face_culling is None: face_culling = material.face_culling if polygon_mode is None: polygon_mode = material.polygon_mode if unlit_color is None: unlit_color = material.unlit_color if line_width is None: line_width = material.line_width if front_face is None: front_face = material.front_face if selectable_mode is None: selectable_mode = material.selectable_mode if use_shader is None: use_shader = material.use_shader if shader_color_normals is None: shader_color_normals = material.shader_color_normals if normal_is_direction is None: normal_is_direction = material.normal_is_direction self.execute( "SetMaterial", objects=self.makeList(objects), ambient=ambient, diffuse=diffuse, emission=emission, specular=specular, shininess=shininess, refresh=int(bool(refresh)), lighting=lighting, smooth_shading=smooth_shading, polygon_filtering=polygon_filtering, depth_buffer=depth_buffer, face_culling=face_culling, polygon_mode=polygon_mode, unlit_color=unlit_color, line_width=line_width, selectable_mode=selectable_mode, front_face=front_face, use_shader=use_shader, shader_color_normals=shader_color_normals, normal_is_direction=normal_is_direction)
[docs] def setObjectPalette(self, objects, palette=None, minVal=None, maxVal=None, palette2=None, minVal2=None, maxVal2=None, mixMethod=None, linMixFactor=None, palette1Dmapping=None, absoluteMode=False, zeroCentered1=None, zeroCentered2=None): """ Assign a palette to objects Parameters ---------- objects: list of AObject Assign palette parameters to these objects palette: APalette or str (name) Principal palette to apply minVal: float (0 - 1) Palette value to assign to objects texture min value (proportionally to palette's limits) maxVal: float (0 - 1) Palette value to assign to objects texture max value palette2: APalette or str (name) Second palette, for 2D textures minVal2: float (0 - 1) Second palette value to affect to object texture second component min value maxVal2: float (0 - 1) Second palette value to assign to object texture second component max value mixMethod: string Method to mix two palettes in a 2D palette : linear or geometric linMixFactor: float mix factor for the linear method palette1Dmapping: string way of using 2D palette for 1D texture : FirstLine or Diagonal absoluteMode: bool if *True*, min/max values are supposed to be absolute values (in regard to objects texture) rather than proportions zeroCentered1: bool min/max should be updated to keep absolute value 0 at the center of the palette (for palette 1). zeroCentered2: bool min/max should be updated to keep absolute value 0 at the center of the palette (for palette 2). """ if isinstance(palette, self.APalette): palette = palette.name cmd = dict(objects=self.makeList(objects), palette=palette, palette2=palette2, min=minVal, max=maxVal, min2=minVal2, max2=maxVal2, mixMethod=mixMethod, linMixFactor=linMixFactor, palette1Dmapping=palette1Dmapping, absoluteMode=int(absoluteMode)) if zeroCentered1 is not None: cmd['zero_centered_axis1'] = int(zeroCentered1) if zeroCentered2 is not None: cmd['zero_centered_axis2'] = int(zeroCentered2) self.execute('SetObjectPalette', **cmd)
# # application control
[docs] def createControlWindow(self): """ Creates anatomist main window. Currently it is done automatically. """ self.execute('CreateControlWindow')
[docs] def close(self): """ Exits Anatomist application. if anatomist is closed, the singleton instance is deleted. So next time the constructor is called, a new instance will be created. """ try: delattr(self.__class__, "_singleton_instance") self.execute('Exit') except: # may fail if it is already closed pass
[docs] def setGraphParams(self, display_mode=None, label_attribute=None, save_only_modified=None, saving_mode=None, selection_color=None, selection_color_inverse=None, set_base_directory=None, show_tooltips=None, use_nomenclature=None): """ Modifies graphs and selections options. Parameters ---------- display_mode: str Paint mode of objects in graph nodes : mesh, bucket, all, first label_attribute: str Selects the attribute used as selection filter: label or name save_only_modified: bool int (0/1) If enabled, graph save saves not all sub objects but only those that have been modified. saving_mode: str Graph saving mode : unchanged (keep the reading format), global (1 file for all same category sub-objects), or local (1 file per sub- object) selection_color: int vector Selected objects color : R G B [A [NA]] (A opacity, NA: 0/1 use object opacity parameter) selection_color_inverse: bool int (0/1) Selection inverses color instead of using selection_color set_base_directory: bool int (0/1) Save subobjects in a directory <graph name>.data show_tooltips: bool int (0/1) Show graph nodes names in tooltips use_nomenclature: bool int (0/1) Enable graph coloring with nomenclature """ self.execute( 'GraphParams', display_mode=display_mode, label_attribute=label_attribute, save_only_modified=save_only_modified, saving_mode=saving_mode, selection_color=selection_color, selection_color_inverse=selection_color_inverse, set_base_directory=set_base_directory, show_tooltips=show_tooltips, use_nomenclature=use_nomenclature)
[docs] def setPaintParams(self, brush_size=None, brush_type=None, follow_linked_cursor=None, line_mode=None, millimeter_mode=None, replace_mode=None, region_transparency=None): """ Setup Paint contol parameters. All parameters are optional. Parameters ---------- brush_size: float Radius of the paint brush, either in millimeters or in voxels, depending on the millimeter_mode. brush_type: str "point", "square", "disk", or "sphere". "ball" is an alias for sphere. follow_linked_cursor: bool Linked cursor moving with brush line_mode: bool line interpolation mode between brush strokes millimeter_mode: bool brush size can be either in mm or in voxels. In voxels mode, the brush may be anisotropic. replace_mode: bool region replacing mode (when drawing on a different region) region_transparency: float value of the region transparency """ if follow_linked_cursor is not None: follow_linked_cursor = int(follow_linked_cursor) if line_mode is not None: line_mode = int(line_mode) if millimeter_mode is not None: millimeter_mode = int(millimeter_mode) if replace_mode is not None: replace_mode = int(replace_mode) self.execute('PaintParams', brush_size=brush_size, brush_type=brush_type, follow_linked_cursor=follow_linked_cursor, line_mode=line_mode, millimeter_mode=millimeter_mode, replace_mode=replace_mode, region_transparency=region_transparency)
# # commands sending
[docs] def execute(self, command, **kwargs): """ Executes a command in anatomist application. It should be a command that can be processed by Anatomist command processor. The list of available commands is in :anadev:`the commands system <commands.html>`. Parameters are converted before sending the request to anatomist application. Parameters ---------- command: str Name of the command to execute. kwargs: dict Parameters for the command """ def ununderscore(k): # this removes a trailing '_' from params names # it allows to used reserved words as params, like raise, by appending # an underscore, like in PyQt4: # a.execute( 'WindowConfig', windows=[w], raise_=1 ) if k.endswith('_'): return k[:-1] return k params = dict((ununderscore(k), self.convertParamsToIDs(v)) for k, v in six.iteritems(kwargs) if v is not None) self.logCommand(command, **params) self.send(command, **params)
def logCommand(self, command, **kwargs): pass def logEvent(self, event, params): pass
[docs] def makeList(thing): """ Transforms the argument into a list: a list with one element if it is not a sequence, or return the input sequence if it is already one """ if isSequenceType(thing): try: if thing.__module__.startswith('anatomist.'): return [thing] except: pass return thing return [thing]
makeList = staticmethod(makeList)
[docs] def convertSingleObjectParamsToIDs(self, item): """ Converts current api object to corresponding anatomist object representation. Parameters ---------- item: AItem Element to convert Returns ------- elements: dict or list Converted elements """ if isinstance(item, Anatomist.AItem): return item.getInternalRep() elif isinstance(item, (six.string_types, int, float, dict)): return item raise TypeError('Expecting an Anatomist object but got one of type %s' % repr(type(item)))
[docs] def convertParamsToIDs(self, params): """ Converts current api objects to corresponding anatomist object representation. This method must be called before sending a command to anatomist application on command parameters. Parameters ---------- params: dict or list Elements to convert Returns ------- elements: dict or list Converted elements """ if not isinstance(params, six.string_types) \ and isSequenceType(params): return [self.convertSingleObjectParamsToIDs(i) for i in params] else: return self.convertSingleObjectParamsToIDs(params)
[docs] def send(self, command, **kwargs): """ Sends a command to anatomist application. Call this method if there is no answer to get. This method depends on the mean of communication with anatomist. Must be redefined in implementation api. Parameters ---------- command: str Name of the command to execute. Any command that can be processed by anatomist command processor. The complete commands list is in :anadev:`the commands system <commands.html>` kwargs: dict Parameters for the command """ pass
[docs] def newItemRep(self): """ Creates a new item representation. This method depends on the mean of communication with anatomist. Must be redefined in implementation api. """ pass
[docs] def sync(self): """ Wait for anatomist finishing current processing. """ pass
[docs] def waitEndProcessing(self): """ Deprecated. Use method sync instead. """ self.sync()
# # logs
[docs] def log(self, message): """ Use this method to print a log message. This method prints on standard output. To be redefined for another type of log. """ print(message)
#
[docs] class AItem(object): """ Base class for representing an object in Anatomist application. Attributes ---------- anatomistinstance: :class:`Anatomist` Reference to Anatomist object which created this object. Useful because some methods defined in AItem objects will need to send a command to the Anatomist application. internalRep: object Representation of this object in anatomist application. ref: bool Indicates if a reference has been taken on the corresponding anatomist object. If *True*, the reference is released on deleting this item. refType: str Type of reference taken on the object : ``Weak`` (reference counter not incremented), ``WeakShared`` (reference counter incremented but the object can be deleted even if it remains references) or ``Strong`` (reference counter is incremented, the object cannot be deleted since there are references on it). If it is not specified, :data:`Anatomist.defaultRefType` is used. """ def __init__(self, anatomistinstance, internalRep=None, refType=None, *args, **kwargs): super(Anatomist.AItem, self).__init__(*args, **kwargs) self.anatomistinstance = anatomistinstance self.refType = refType if internalRep is None: internalRep = anatomistinstance.newItemRep() if isinstance(internalRep, Anatomist.AItem): # avoid recursion self.internalRep = internalRep.internalRep else: self.internalRep = internalRep self.ref = False def __repr__(self): """ String representation of the object. """ return str(self.internalRep) def __cmp__(self, other): """ Called on comparison operations between self and other. Their internalRep is compared. Returns ------- cmp: int -1 if self < other, 0 if self == other, 1 if self > other """ if not isinstance(other, Anatomist.AItem): return 1 if self.internalRep == other.internalRep: return 0 elif self.internalRep < other.internalRep: return -1 else: return 1 def __eq__(self, other): """ Equality operator for python3 """ if not isinstance(other, Anatomist.AItem): return False return self.internalRep == other.internalRep def __hash__(self): # a bit dangerous since internalRep is mutable. # but, welll, we never change it, do we ? # # ylep 2020-03-20: shouldn't we return # hash((self.anatomistinstance, self.internalRep, self.refType, # self.ref)) instead? return id(self.internalRep) def __lt__(self, other): """ Comparison operator for python3 """ if not isinstance(other, Anatomist.AItem): return False return self.internalRep < other.internalRep def __gt__(self, other): """ Comparison operator for python3 """ if not isinstance(other, Anatomist.AItem): return False return self.internalRep > other.internalRep
[docs] def getInfo(self): """ Gets information about this object. Returns ------- info: dictionary information about the object (property -> value) """ pass
[docs] def getInfos(self): ''' Obsolete - now use getInfo() ''' return self.getInfo()
[docs] def takeRef(self): """ Take a reference on this object. """ # print "take ref ", self.refType, self, self.__class__ self.ref = True
[docs] def releaseRef(self): """ Release a reference on this object. """ # print "release ref", self, self.__class__ self.ref = False
[docs] def releaseAppRef(self): """ Release anatomist application reference on this object: so object life is controled by references on it. If there is no more references on the object, it is deleted. Used when an object is created by python api. It is not owned by anatomist application. """ pass
[docs] def takeAppRef(self): """ Take anatomist application reference on this object : so object life is controled the normal way by Anatomist. Inverse of releaseAppRef(). The object is now owned by anatomist application. """ pass
[docs] def getRef(self, refType): """ Get a reference of type *refType* on this object. Returns ------- ref: AItem A copy of current object with a reference of type *refType* on anatomist object. """ # print "get ref ", self, self.__class__ return self.__class__(self.anatomistinstance, self.getInternalRep(), refType)
def __del__(self): """ Called when current object is deleted (when it is no more referenced). If a reference had been taken on anatomist corresponding object, it is released. """ # print "del ", self, self.__class__ if self.ref: try: # can fail if Anatomist is already closed self.releaseRef() except: pass
[docs] def getInternalRep(self): """ Returns internal representation of the object (implementation dependant). """ return self.internalRep
def makeList(self, objects): return self.anatomistinstance.makeList(objects)
#
[docs] class AObject(AItem): """ Represents an object in Anatomist application. Following information can be obtained using ObjectInfo command : Attributes ---------- objectType: str object type. For example: volume, bucket, graph, texture... children: list of :class:`Anatomist.AObject` List of objects which are children of current object (for example: nodes in a graph). Can be empty. filename: str Name of the file from which the object has been loaded. May be *None*. name: str Name of the object presented in Anatomist window. copy: bool *True* indicates that this object is a copy of another object, otherwise it is the original object. material: :class:`Anatomist.Material` Object material parameters referential: :class:`Anatomist.Referential` Referential assigned to this object. """ def __init__(self, anatomistinstance, internalRep=None, *args, **kwargs): """ If internal rep is given as parameter, the corresponding anatomist object already exists: take a reference on it (to prevent its deletion). """ super(Anatomist.AObject, self).__init__( anatomistinstance, internalRep, *args, **kwargs) if internalRep is not None: self.takeRef()
[docs] def getWindows(self): """ Gets windows that contain this object. Returns ------- windows: list of :class:`Anatomist.AWindow` Open windows that contain this object. """ allWindows = self.anatomistinstance.importWindows() windows = [] for w in allWindows: objs = w.objects if self in objs: windows.append(w) return windows
# object manipulation
[docs] def addInWindows(self, windows, temporary=False, position=-1): """ Adds the object in windows. Windows must already exist. Parameters ---------- windows: list of :class:`Anatomist.AWindow` List of windows in which the object must be added temporary: bool (optional) temporary object do not affect the view boundaries and camera settings position: int (optional) insert objects as this order number """ self.anatomistinstance.addObjects( [self], windows, temporary=temporary, position=position)
[docs] def removeFromWindows(self, windows): """ Removes object from windows. Parameters ---------- windows: list of :class:`Anatomist.AWindow` List of windows from which the object must be removed """ self.anatomistinstance.removeObjects([self], windows)
[docs] def delete(self): """ Deletes object """ self.anatomistinstance.deleteObjects([self])
[docs] def assignReferential(self, referential): """ Assign a referential to object. The referential must exist. To create a new Referential, execute createReferential, to assign the central referential, first get it with Anatomist.centralRef attribute. Parameters ---------- referential: Referential The referential to be assigned to the object """ self.anatomistinstance.assignReferential(referential, [self])
[docs] def loadReferentialFromHeader(self): """ Extract information about referential and transformations from the header of the object and assign the found referential. """ self.anatomistinstance.loadReferentialFromHeader([self])
applyBuiltinReferential = loadReferentialFromHeader
[docs] def setMaterial(self, material=None, refresh=True, ambient=None, diffuse=None, emission=None, specular=None, shininess=None, lighting=None, smooth_shading=None, polygon_filtering=None, depth_buffer=None, face_culling=None, polygon_mode=None, unlit_color=None, line_width=None, ghost=None, front_face=None, selectable_mode=None, use_shader=None, shader_color_normals=None, normal_is_direction=None): """ Changes object material properties. Parameters ---------- material: Material Material characteristics, including render properties. The material may be specified as a Material object, or as its various properties (ambient, diffuse, etc.). If both a material parameter and other properties are specified, the material is used as a base, and properties are used to modify it refresh: bool If *True*, force windows refreshing ambient: list RGB[A] vector: float values between 0 and 1. diffuse: list RGB[A] vector: float values between 0 and 1. This parameter corresponds to the "standard" notion of color emission: list RGB[A] vector: float values between 0 and 1. specular: list RGB[A] vector: float values between 0 and 1. shininess: float 0-124 lighting: int enables (1) or disables (0) objects lighting/shading. Setting this value to -1 goes back to the default mode (globally set at the view/scene level). smooth_shading: int (tristate: 0/1/-1) smooth or flat polygons mode polygon_filtering: int (tristate: 0/1/-1) filtering (antialiasing) of lines/polygons depth_buffer: int (tristate: 0/1/-1) enables/disables writing in the Z-buffer. You can disable it if you want to click "through" an object (but it may have strange effects on the rendering) face_culling: int (tristate: 0/1/-1) don't draw polygons seen from the back side. The best is to enable it for transparent objects, and to disable it for "open" (on which both sides may be seen) and opaque meshes. For objects both open and transparent, there is no perfoect setting... polygon_mode: string polygons rendering mode: "normal", "wireframe", "outline" (normal + wireframe), "hiddenface_wireframe" (wireframe with hidden faces), "default" (use the global view settings), "ext_outlined" (thickened external boundaries + normal rendering). unlit_color: RGB[A] vector: float values between 0 and 1. color used for lines when lighting is off. For now it only affects polygons boundaries in "outlined" or "ext_outlined" polygon modes. line_width: float Lines thickness (meshes, segments, wireframe rendering modes). A null or negative value fallsback to default (1 in principle). front_face: string Specifies if the mesh(es) polygons external face is the clockwise or counterclockwise side. Normally in Aims/Anatomist indirect referentials, polygons are in clockwise orientation. Values are "clockwise", "counterclockwise", or "neutral" (the default). selectable_mode: string New in Anatomist 4.5. Replaces the ghost property. **always_selectable**: object is selecatble whatever its opacity. **ghost**: object is not selectable. **selectable_when_opaque**: object is selectable when totally opaque (this is the default in Anatomist). **selectable_when_not_totally_transparent**: object is selectable unless opacity is zero. use_shader: int enable or disable the use of OpenGL shaders for this object. shader_color_normals: int when shaders are enabled, normals can be represented as colors on the object. normal_is_direction: int when shaders are enabled and shader_color_normals is set, normals may be pre-calculates as mesh direction, on a "line" mesh (polygons are lines, not triangles). """ self.anatomistinstance.setMaterial( [self], material, refresh, ambient, diffuse, emission, specular, shininess, lighting, smooth_shading, polygon_filtering, depth_buffer, face_culling, polygon_mode, unlit_color, line_width, ghost=None, front_face=front_face, selectable_mode=selectable_mode, use_shader=use_shader, shader_color_normals=shader_color_normals, normal_is_direction=normal_is_direction)
[docs] def setPalette(self, palette=None, minVal=None, maxVal=None, palette2=None, minVal2=None, maxVal2=None, mixMethod=None, linMixFactor=None, palette1Dmapping=None, absoluteMode=False, zeroCentered1=None, zeroCentered2=None): """ Assign a palette to object, or change its characteristics (scaling etc). Parameters ---------- palette: Anatomist.APalette or str (name) Principal palette to apply minVal: float Minimum object texture value mapped to the lower bound of the palette, by default in relative proportional mode. maxVal: float Minimum object texture value mapped to the lower bound of the palette. By default minVal, maxVal, minVal2 and maxVal2 are relative values expressed in proportion of object texture extrema: [0-1] corresponds to the whole object dynamics. If absoluteMode is True, then values are in object texture values space. The range [minVal-maxVal] is mapped to the while palette, thus any value below or over these extrema will get the first or last (resp.) color of the palette. Values outside [0-1] may be used, meaning that not all the palette colors range will be mapped to the texture values. palette2: APalette Second palette, for 2D textures minVal2: float (0 - 1) Second palette value to affect to object texture second component min value maxVal2: float (0 - 1) Second palette value to assign to object texture second component max value mixMethod: string Method to mix two palettes in a 2D palette: linear or geometric linMixFactor: float mix factor for the linear method palette1Dmapping: string way of using 2D palette for 1D texture : FirstLine or Diagonal absoluteMode: bool if *True*, min/max values are supposed to be absolute values (in regard to objects texture) rather than proportions zeroCentered1: bool min/max should be updated to keep absolute value 0 at the center of the palette (for palette 1). zeroCentered2: bool min/max should be updated to keep absolute value 0 at the center of the palette (for palette 2). """ self.anatomistinstance.setObjectPalette( [self], palette, minVal, maxVal, palette2, minVal2, maxVal2, mixMethod, linMixFactor, palette1Dmapping, absoluteMode=absoluteMode, zeroCentered1=zeroCentered1, zeroCentered2=zeroCentered2)
[docs] def extractTexture(self, time=None): """ Extract the object texture to create a new texture object. Parameters ---------- time: float For temporal objects, if this parameter is mentionned the texture will be extracted at this time. if not mentionned, All times will be extracted and the texture will be a temporal object. In socket implementation, it is necessary to get a new id for the texture object and to pass it to the command. Returns ------- texture: AObject The newly created texture object """ pass
[docs] def generateTexture(self, dimension=1): """ Generates an empty texture (value 0 everywhere) for a mesh object. Parameters ---------- dimension: int Texture dimension (1 or 2) Returns ------- texture: AObject The newly created texture object """ pass
[docs] def exportTexture(self, filename, time=None): """ Saves the texture of an object to a file Parameters ---------- filename: str File in which the texture must be written time: float For temporal objects, if this parameter is mentionned the texture will be extracted at this time. if not mentionned, all times will be extracted and the texture will be a temporal object. """ self.anatomistinstance.execute( "ExportTexture", filename=filename, object=self, time=time)
[docs] def save(self, filename=None): """ Saves object in a file. Parameters ---------- filename: str File in which the object will be written. If not mentionned, the object is saved in the file from which it has been loaded. """ self.anatomistinstance.execute( "SaveObject", object=self, filename=filename)
[docs] def reload(self): """ Reload this object already in memory reading its file. """ self.anatomistinstance.reloadObjects([self])
#
[docs] class AGraph(AObject): """ Graph object in Anatomist. """ def __init__(self, anatomistinstance, internalRep=None, *args, **kwargs): super(Anatomist.AGraph, self).__init__( anatomistinstance, internalRep, *args, **kwargs)
[docs] def createNode(self, name=None, syntax=None, with_bucket=None, duplicate=True): """ Creates a new node with optionally an empty bucket inside and adds it in the graph. Parameters ---------- name: str node name. default is ``RoiArg``. syntax: str node syntax attribute. default is ``roi``. with_bucket: bool if *True*, creates an empty bucket in the node and returns it with the node. default is None, so the bucket is created but not returned duplicate: bool enables duplication of nodes with the same name attribute. Returns ------- node: (AObject, AObject) (the created node, the created bucket) or only the created node if with_bucket is False """ pass
[docs] class AWindow(AItem): """ Represents an anatomist window. Attributes ---------- windowType: str Window type (``'axial'``, ``'sagittal'``, ...) group: :class:`Anatomist.AWindowsGroup` The group which this window belongs to. objects: List of :class:`Anatomist.AObject` The window contains these objects. block: :class:`Anatomist.AWindowsBlock` The block in which the window is contained, None if it is not in a block. """ def __init__(self, anatomistinstance, internalRep=None, *args, **kwargs): """ If internal rep is given in parameter, the corresponding anatomist window already exists : take a reference on it (to prevent its deletion). """ super(Anatomist.AWindow, self).__init__( anatomistinstance, internalRep, *args, **kwargs) if internalRep is not None: self.takeRef() # We need to keep a reference on the windows block in which the # window is to prevent it to be deleted before the window. # Indeed, there is no reference count for windows blocks, they are # only classical QWidgets. self.block = None
[docs] def addObjects(self, objects, add_children=False, add_graph_nodes=True, add_graph_relations=False, temporary=False, position=-1): """ Adds objects in window. Parameters ---------- objects: list of :class:`Anatomist.AObject` List of objects to add temporary: bool (optional) temporary object do not affect the view boundaries and camera settings position: int (optional) insert objects as this order number """ self.anatomistinstance.addObjects(objects, [self], add_children, add_graph_nodes, add_graph_relations, temporary=temporary, position=position)
[docs] def removeObjects(self, objects): """ Removes objects from window. Parameters ---------- objects: list of :class:`Anatomist.AObject` List of objects to remove """ self.anatomistinstance.removeObjects(objects, [self])
[docs] def camera( self, zoom=None, observer_position=None, view_quaternion=None, slice_quaternion=None, force_redraw=None, cursor_position=None, boundingbox_min=None, boundingbox_max=None, slice_orientation=None): """ Sets the point of view, zoom, cursor position for a 3D window. Parameters ---------- zoom: float Zoom factor, default is 1 observer_position: float vector, size 3 Camera position view_quaternion: float vector, size 4, normed View rotation slice_quaternion: float vector, size 4, normed Slice plan rotation force_redraw: bool If *True*, refresh printing immediatly, default is *False* cursor_position: float vector Linked cursor position boundingbox_min: float vector Bounding box min values boundingbox_max: float vector Bounding box max values slice_orientation: float vector, size 3 Slice plane orientation, normal to the plane """ self.anatomistinstance.camera([self], zoom, observer_position, view_quaternion, slice_quaternion, force_redraw, cursor_position, boundingbox_min, boundingbox_max, slice_orientation=slice_orientation)
[docs] def windowConfig(self, clipping=None, clip_distance=None, cursor_visibility=None, face_culling=None, flat_shading=None, fog=None, geometry=None, iconify=None, light=None, linkedcursor_on_slider_change=None, perspective=None, perspective_angle=None, perspective_auto_far_plane=None, perspective_far_distance=None, perspective_near_ratio=None, polygon_filtering=None, polygon_mode=None, polygons_depth_sorting=None, raise_window=None, record_basename=None, record_mode=None, snapshot=None, transparent_depth_buffer=None, view_size=None, fullscreen=None, show_cursor_position=None, show_toolbars=None, snapshot_width=None, snapshot_height=None): """Settings for windows (includes various settings) Parameters ---------- clipping: int (optional) number of clipping planes: 0, 1 or 2 clip_distance: float (optional) distance between the slice plane and the clipping planes cursor_visibility: int (optional) makes visible (1) or invisible (0) the linked cursor in the chosen windows. The value -1 sets back the global setting (of the preferences) face_culling: int (optional) enables (1) or disables (0) the elimination of polygons seen from the bottom face flat_shading: int (optional) enables (1) or disables (0) rendering in "flat shading" mode (without color smoothing) fog: int (optional) enables (1) or disables (0) fog geometry: list of int (optional) position and size of the window (external size). If sizes are zero or not specified, the current window size is not changed iconify: int (optional) iconifies (or hides) windows light: dict (optional) Windows lighting settings. This dictionary may include the following parameters: * ambient: ambiant lighting settings (list of float, 4 elements) * diffuse: diffuse lighting settings (list of float, 4 elements) * specular: specular lighting settings (list of float, 4 elements) * background: background color (list of float, 4 elements) * position: light position (list of float, 4 elements) * spot_direction: spot light direction (list of float, 3 elements) * spot_exponent: spot light intensity exponent (float) * spot_cutoff: spot light cutoff angle (float) * attenuation_offset: light attenuation, offset part ( float) * attenuation_linear: light attenuation, linear coefficient (float) * attenuation_quadratic: light attenuation, quadratic coefficient (float) * model_ambient: don't really know... (list of float, 4 elements) * model_local_viewer: don't really know... (float) * model_two_side: don't really know (float) linkedcursor_on_slider_change: int (optional) enables or disables the mode when slice/time sliders act as linked cursor actions (with propagation to other views) perspective: int (optional) enables (1) or disables (0) the perspective rendering mode perspective_angle: float (optional) set the perspective view angle (low: more isometric, high: more distorted). Only used when perspective is enabled. perspective_auto_far_plane: int (optional) enables (1) or disables (0) the automatic perspective far clipping plane setup. Only used when perspective is enabled. perspective_far_distance: float (optional) set the clipping distance from the eye. Only used when perspective is enabled and perspective_auto_far_plane is disabled. perspective_near_ratio: float (optional) set the minimum ratio between the near clipping plane distance and the far one. Objects nearer than this near plane will not be displayed. But reducing this ratio lowers the precision of the depth buffer. Default is 0.01. Only used when perspective is enabled. polygon_filtering: int (optional) enables (1) or disables (0) polygons and lines smoothing (anti- aliasing) polygon_mode: string (optional) polygons rendering mode: "normal", "wireframe", "outline" (normal + wireframe), "hiddenface_wireframe" (wireframe with hidden faces) polygons_depth_sorting: int (optional) enables (1) or disables (0) polygons sortig along depth on transparent objects to allow a better rendering. This mode has a large impact on performances, so use it with care. raise_window: int (optional) unicognifies windows and make them move to the top of the desktop. Note that this parameter has a different name as the anatomist command interface (is was "raise" there) because "raise" is a reserved keyword in Python and cannot be used here. record_basename: string (optional): base filename of images written using the film recording mode (ex: ``/tmp/toto.jpg``). Images will actually have numbers appended before the extension record_mode: int (optional) enables (1) or disables (0) the images recording mode (film) of 3D windows. To enable it, record_basename must also be specified snapshot: string (optional) Saves the image of the view in the specified file. If windows contains several values, then several images have to be saved: in this case, snapshot is a list of filenames separated by space characters: so the file name/path must not contain any space character (this restriction doesn't apply if a single window is used). Node: escape character ("\ ") are not supported yet. snapshot_width: int (optional) Snapshot or recorded images width. If unspecified, fit the window size. New in Anatomist 4.6. snapshot_height: int (optional) Snapshot or recorded images height. If unspecified, fit the window size. New in Anatomist 4.6. transparent_depth_buffer: int (optional) enables (1) or disables (0) writing of transparent objects in the depth buffer. Useful if you want to click across transparents objects (but the rendering can be wrong) view_size: list of int (optional) size of the rendering zone (3D rendering widget). This parameter has a higher priority than sizes given using geometry if both are specified fullscreen: int (optional) enables or disables the fullscreen mode show_cursor_position: int (optional) shows or hides the status bar at the bottom of the window, showing the cursor position and a current object value at this position. show_toolbars: int (optional) shows or hides everything around the 3D view (menus, buttons bars, status bar, referential...) """ self.anatomistinstance.execute( "WindowConfig", windows=[self], clipping=clipping, clip_distance=clip_distance, cursor_visibility=cursor_visibility, face_culling=face_culling, flat_shading=flat_shading, fog=fog, geometry=geometry, iconify=iconify, light=light, linkedcursor_on_slider_change=linkedcursor_on_slider_change, perspective=perspective, perspective_angle=perspective_angle, perspective_auto_far_plane=perspective_auto_far_plane, perspective_far_distance=perspective_far_distance, perspective_near_ratio=perspective_near_ratio, polygon_filtering=polygon_filtering, polygon_mode=polygon_mode, polygons_depth_sorting=polygons_depth_sorting, raise_=raise_window, record_basename=record_basename, record_mode=record_mode, snapshot=snapshot, transparent_depth_buffer=transparent_depth_buffer, view_size=view_size, fullscreen=fullscreen, show_cursor_position=show_cursor_position, show_toolbars=show_toolbars)
[docs] def snapshot(self, filename, width=None, height=None): """Take a snapshot of the window 3D contents and save it into a file Equivalent to: :: window.windowConfig(snapshot=filename, snapshot_width=width, snapshot_height=height) Parameters ---------- filename: str file name to save the snapshot into width: int width of the snapshot. If unspecified, or if framebuffer rendering is not supported by the OpenGL implementation, the width will always be the actual visible window width. height: int height of the snapshot. If unspecified, or if framebuffer rendering is not supported by the OpenGL implementation, the height will always be the actual visible window height. """ self.anatomistinstance.execute("WindowConfig", windows=[self], snapshot=filename, snapshot_width=width, snapshot_height=height)
[docs] def assignReferential(self, referential): """ Assign a referential to window. The referential must exist. To create a new Referential, execute createReferential, to assign the central referential, first get it with Anatomist.centralRef attribute. Parameters ---------- referential: :class:`Anatomist.Referential` The referential to assign to objects and/or windows """ self.anatomistinstance.assignReferential(referential, [self])
[docs] def getReferential(self): """ Get the referential attached to the window (the coordinates system used for 3D positions in this window) """ pass
[docs] def moveLinkedCursor(self, position): """ Changes cursor position in this window and all linked windows (same group). Parameters ---------- position: float vector, size 3 Cursor new position """ self.anatomistinstance.execute( "LinkedCursor", window=self, position=position)
[docs] def showToolbox(self, show=True): """ Shows or hides the toolbox frame of a window. Parameters ---------- show: bool If *True*, the window's toolbox frame is shown, else it is hidden. """ if show: show = 1 else: show = 0 self.anatomistinstance.execute( "ControlsParams", window=self, show=show)
[docs] def setControl(self, control): """ Changes the selected button in windows menu. Examples of controls : ``'PaintControl'``, ``'NodeSelectionControl'``, ``'Default 3D Control'``, ``'Selection 3D'``, ``'Flight Control'``, ``'ObliqueControl'``, ``'TransformationControl'``, ``'CutControl'``, ``'Browser Selection'``, ``'RoiControl'``... """ self.anatomistinstance.setWindowsControl( windows=[self], control=control)
[docs] def close(self): """ Closes window. """ self.anatomistinstance.closeWindows([self])
[docs] def activateAction(self, action_type, method, **kwargs): """ Triggers window action activation. New in Anatomist 4.5. Parameters ---------- action_type: str (mandatory) type of action: "key_press", "key_release", "mouse_press", "mouse_release", "mouse_double_click", "mouse_move". Additional parameters depend on the action type: * key actions do not use any; * mouse actions need x and y keyword parameters method: str (mandatory) action method name, as registered in the active control. Deteremines what will actually be done. x: int (optional) x mouse coord, for mouse actions only. y: int (optional) y mouse coord, for mouse actions only. """ self.anatomistinstance.execute('ActivateAction', window=self, action_type=action_type, method=method, **kwargs)
#
[docs] class AWindowsBlock(AItem): """ A window containing other windows. Attributes ---------- nbCols: int Number of columns of the windows block """ def __init__(self, anatomistinstance=None, internalRep=None, nbCols=0, nbRows=0, *args, **kwargs): super(Anatomist.AWindowsBlock, self).__init__( anatomistinstance, internalRep, *args, **kwargs) self.nbCols = nbCols self.nbRows = nbRows def setColumns(self, nCol): self.nbCols = nCol self.rnRows = 0 self.anatomistinstance.execute( 'WindowBlock', block=self.internalRep, block_columns=nCol) def setRows(self, nRow): self.nbRows = nRow self.nbCols = 0 self.anatomistinstance.execute( 'WindowBlock', block=self.internalRep, block_rows=nRow) def arrangeInRect(self, widthHeightRatio=1.): self.anatomistinstance.execute( 'WindowBlock', block=self.internalRep, make_rectangle=1, rectangle_ratio=widthHeightRatio)
#
[docs] class AWindowsGroup(AItem): """ A group containing several windows which are linked. Moving cursor in one window moves it in all linked windows. Its *internalRep* is the group id (int). """ def __init__(self, anatomistinstance, internalRep=None, *args, **kwargs): super(Anatomist.AWindowsGroup, self).__init__( anatomistinstance, internalRep, *args, **kwargs)
[docs] def getSelection(self): """ Returns ------- objects: list of :class:`Anatomist.AObject` Objects that are selected in this windows group """ return self.anatomistinstance.getSelection(self)
[docs] def isSelected(self, object): """ Parameters ---------- object: AObject An object in this windows group Returns ------- selected: bool *True* if the object is selected in this windows group """ selectedObjects = self.getSelection() return (selectedObjects is not None) \ and (object in selectedObjects)
[docs] def setSelection(self, objects): """ Initializes selection with given objects for this windows group. Parameters ---------- objects: list of :class:`Anatomist.AObject` Objects to select """ self.anatomistinstance.execute( "Select", objects=self.makeList(objects), group=self, modifiers="set")
[docs] def addToSelection(self, objects): """ Adds objects to this windows group's current selection. Parameters ---------- objects: list of :class:`Anatomist.AObject` Objects to add to selection """ self.anatomistinstance.execute( "Select", objects=self.makeList(objects), group=self, modifiers="add")
[docs] def unSelect(self, objects): """ Removes objects from this windows group selection. Parameters ---------- objects: list of :class:`Anatomist.AObject` Objects to unselect """ self.anatomistinstance.execute( "Select", unselect_objects=self.makeList(objects), group=self, modifiers="add")
[docs] def toggleSelection(self, objects): """ Inverses selection in this windows group. Selected objects becomes unselected, unselected objects become selected. """ self.anatomistinstance.execute( "Select", objects=self.makeList(objects), group=self, modifiers="toggle")
[docs] def setSelectionByNomenclature(self, nomenclature, names): """ Selects objects giving their name in a nomenclature. In anatomist graphical interface, it is done by clicking on items of a nomenclature opened in a browser. Parameters ---------- nomenclature: AObject tree with names and labels associated to nodes. names: list of str Names of elements to select. """ if names is not None and names != []: # executing the command with names = [] make errors snames = ' '.join(names) self.anatomistinstance.execute( "SelectByNomenclature", nomenclature=nomenclature, names=snames, group=self, modifiers="set")
[docs] def addToSelectionByNomenclature(self, nomenclature, names): """ Adds objects to this windows group's current selection, given their name in a nomenclature. Parameters ---------- nomenclature: AObject Tree with names and labels associated to nodes. names: list of str Names of elements to add to selection. """ if names is not None and names != []: snames = ' '.join(names) self.anatomistinstance.execute( "SelectByNomenclature", nomenclature=nomenclature, names=snames, group=self, modifiers="add")
[docs] def toggleSelectionByNomenclature(self, nomenclature, names): """ Removes objects from this windows group's selection, given their name in a nomenclature. Parameters ---------- nomenclature: AObject Tree with names and labels associated to nodes. names: list of str Names of elements to unselect. """ if names is not None and names != []: snames = ' '.join(names) self.anatomistinstance.execute( "SelectByNomenclature", nomenclature=nomenclature, names=snames, group=self, modifiers="toggle")
#
[docs] class Referential(AItem): """ Attributes ---------- refUuid: str A unique id representing this referential Two referentials are equal if they have the same uuid. """ def __init__(self, anatomistinstance, internalRep=None, uuid=None, *args, **kwargs): super(Anatomist.Referential, self).__init__( anatomistinstance, internalRep, *args, **kwargs) if uuid is not None: self.refUuid = uuid def __cmp__(self, other): """ Called on comparison operations between self and other. Their uuid is compared. Returns ------- cmp: int -1 if self < other, 0 if self == other, 1 if self > other """ if not isinstance(other, Anatomist.Referential): return 1 if self.refUuid == other.refUuid: return 0 elif self.refUuid < other.refUuid: return -1 else: return 1 def __eq__(self, other): if not isinstance(other, Anatomist.Referential): return False return self.refUuid == other.refUuid def __hash__(self): # needs overriding in python3, since: # "a class that overrides __eq__() and does not define __hash__() # will have its __hash__() implicitly set to None" return AItem.__hash__(self) def __lt__(self, other): if not isinstance(other, Anatomist.Referential): return False return self.refUuid < other.refUuid def __gt__(self, other): if not isinstance(other, Anatomist.Referential): return False return self.refUuid > other.refUuid
#
[docs] class APalette(AItem): """ Attributes ---------- name: str Palette name. Must be unique, it is the palette identifier. """ def __init__(self, name, anatomistinstance, internalRep=None, *args, **kwargs): super( Anatomist.APalette, self).__init__(anatomistinstance, internalRep, *args, **kwargs) self.name = name
[docs] def setColors(self, colors, color_mode="RGB"): """ Modifies a palette (colors). Parameters ---------- colors: list of int Color vectors, in line (a list of R, G, B, R, G, B... or R, G, B, A, ..), as int 8 bit values color_mode: str ``'RGB'`` or ``'RGBA'`` """ self.anatomistinstance.execute("ChangePalette", name=self.name, colors=colors, color_mode=color_mode)
#
[docs] class Transformation(AItem): """ This objects contains information to convert coordinates from one referential to another. """ def __init__(self, anatomistinstance, internalRep=None, *args, **kwargs): super(Anatomist.Transformation, self).__init__( anatomistinstance, internalRep, *args, **kwargs)
[docs] def save(self, filename): """ Saves transformation in a file. Parameters ---------- filename: str File in which the transformation will be written. """ self.anatomistinstance.execute( "SaveTransformation", filename=filename, transformation=self)
#
[docs] class Material(object): """ Attributes ---------- ambient: list RGB[A] vector: float values between 0 and 1. diffuse: list RGB[A] vector: float values between 0 and 1. This parameter corresponds to the "standard" notion of color emission: list RGB[A] vector: float values between 0 and 1. specular: list RGB[A] vector: float values between 0 and 1. shininess: float 0-124 lighting: int enables (1) or disables (0) objects lighting/shading. Setting this value to -1 goes back to the default mode (globally set at the view/scene level). smooth_shading: int (tristate: 0/1/-1) smooth or flat polygons mode polygon_filtering: int (tristate: 0/1/-1) filtering (antialiasing) of lines/polygons depth_buffer: int (tristate: 0/1/-1) enables/disables writing in the Z-buffer. You can disable it if you want to click "through" an object (but it may have strange effects on the rendering) face_culling: int (tristate: 0/1/-1) don't draw polygons seen from the back side. The best is to enable it for transparent objects, and to disable it for "open" (on which both sides may be seen) and opaque meshes. For objects both open and transparent, there is no perfoect setting... polygon_mode: string polygons rendering mode: "normal", "wireframe", "outline" (normal + wireframe), "hiddenface_wireframe" (wireframe with hidden faces), "default" (use the global view settings), "ext_outlined" (thickened external boundaries + normal rendering). unlit_color: RGB[A] vector: float values between 0 and 1. color used for lines when lighting is off. For now it only affects polygons boundaries in "outlined" or "ext_outlined" polygon modes. line_width: float Lines thickness (meshes, segments, wireframe rendering modes). A null or negative value fallsback to default (1 in principle). front_face: string Specifies if the mesh(es) polygons external face is the clockwise or counterclockwise side. Normally in Aims/Anatomist indirect referentials, polygons are in clockwise orientation. Values are "clockwise", "counterclockwise", or "neutral" (the default). selectable_mode: string New in Anatomist 4.5. Replaces the ghost property. **always_selectable**: object is selecatble whatever its opacity. **ghost**: object is not selectable. **selectable_when_opaque**: object is selectable when totally opaque (this is the default in Anatomist). **selectable_when_not_totally_transparent**: object is selectable unless opacity is zero. use_shader: int enable or disable the use of OpenGL shaders for this object. shader_color_normals: int when shaders are enabled, normals can be represented as colors on the object. normal_is_direction: int when shaders are enabled and shader_color_normals is set, normals may be pre-calculates as mesh direction, on a "line" mesh (polygons are lines, not triangles). """ def __init__(self, ambient=None, diffuse=None, emission=None, shininess=None, specular=None, lighting=None, smooth_shading=None, polygon_filtering=None, depth_buffer=None, face_culling=None, polygon_mode=None, unlit_color=None, line_width=None, ghost=None, front_face=None, selectable_mode=None, use_shader=None, shader_color_normals=None, normal_is_direction=None): self.ambient = ambient self.diffuse = diffuse self.emission = emission self.shininess = shininess self.specular = specular # render properties self.lighting = lighting self.smooth_shading = smooth_shading self.polygon_filtering = polygon_filtering self.depth_buffer = depth_buffer self.face_culling = face_culling self.polygon_mode = polygon_mode self.unlit_color = unlit_color self.line_width = line_width self.selectable_mode = selectable_mode if ghost and self.selectable_mode is None: self.selectable_mode = 'ghost' self.front_face = front_face self.use_shader = use_shader self.shader_color_normals = shader_color_normals self.normal_is_direction = normal_is_direction def __repr__(self): return "{ambient: " + str(self.ambient) \ + ", diffuse: " + str(self.diffuse) \ + ", emission : " + str(self.emission) \ + ", shininess: " + str(self.shininess) \ + ", specular: " + str(self.specular) \ + ", lighting: " + str(self.lighting) \ + ", smooth_shading: " + str(self.smooth_shading) \ + ", polygon_filtering: " + str(self.polygon_filtering) \ + ", depth_buffer: " + str(self.depth_buffer) \ + ", face_culling: " + str(self.face_culling) \ + ", polygon_mode: " + str(self.polygon_mode) \ + ", unlit_color: " + str(self.unlit_color) \ + ", line_width: " + str(self.line_width) \ + ", selectable_mode: " + str(self.selectable_mode) \ + ", front_face: " + str(self.front_face) \ + ", use_shader: " + str(self.use_shader) \ + ", shader_color_normals: " + str(self.shader_color_normals) \ + ", normal_is_direction: " + str(self.normal_is_direction) \ + "}"