# region gplv3preamble
# The Medical Simulation Markup Language (MSML) - Simplifying the biomechanical modeling workflow
#
# MSML has been developed in the framework of 'SFB TRR 125 Cognition-Guided Surgery'
#
# If you use this software in academic work, please cite the paper:
# S. Suwelack, M. Stoll, S. Schalck, N.Schoch, R. Dillmann, R. Bendl, V. Heuveline and S. Speidel,
# The Medical Simulation Markup Language (MSML) - Simplifying the biomechanical modeling workflow,
# Medicine Meets Virtual Reality (MMVR) 2014
#
# Copyright (C) 2013-2014 see Authors.txt
#
# If you have any questions please feel free to contact us at suwelack@kit.edu
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# endregion
__author__ = 'Alexander Weigl'
from ..model import *
from ..exceptions import *
import msml.sortdef
from .. import log
from .features import get_needed_features
class ExporterOutputVariable(MSMLVariable):
pass
[docs]class Exporter(object):
def __init__(self, msml_file):
"""Create a new exporter instance.
This exporter is the base for your exporter developments
and can be used as an NOOP-Exporter.
If you derive this class, you should call :py:func:`self.initialize(...)`
"""
assert isinstance(msml_file, MSMLFile)
self.initialize(msml_file)
[docs] def initialize(self, msml_file, name = "base",
output_type_of_elements = None,
features = frozenset(),
mesh_sort = ("VTK", "Mesh")):
"""Call this in derived classes for initializing the input, output and arguments structures.
:param msml_file: the given msml in the constructor
:type msml_file: msml.model.base.MSMLFile
:param name: a name for your exporter
:type name: str
:param output_type_of_elements: a dictionary of dictionaries for every element and parameter
:type output_type_of_elements: dict[str, dict[str, msml.sorts.Sort]]
:param features: a list of string with supported features
:type features: set
:param mesh_sort: a tuple of (physical, logical) type name
:type mesh_sort: tuple[str, str]
:return:
"""
self._datamodel = None
self._msml_file = msml_file
self.name = name
self._output_types_of_elements = output_type_of_elements
self.id = "__exporter__"
self.mesh_sort = mesh_sort
"""The physical and logical sort of the input mesh"""
self._output = {}
"""Output slots (meta data)
:type dict[str, Slot]"""
self._input = {}
"""Input slots (meta data)
:type dict[str, Slot]"""
self._attributes = {}
"""Attribute values for input slots, in the manner
bunny_mesh_1 = "${bunnyVolumeMesher.mesh}"
:type dict[str,str]"""
self.arguments = {}
"""stores the References to the input values
:type dict[str,Reference]
:see Exporter.link
"""
self._features = features
"""Set of supported features from this exporter
:see :py:meth:`Exporter.match_features`
:type set[str]
"""
self.gather_output()
self.gather_inputs()
@property
def features(self):
return self._features
@features.setter
def features(self, value):
self._features = value
[docs] def lookup(self, ref, outarg):
assert isinstance(ref, Reference)
obj = ref.task
slot = ref.slot
for scene_object in self._msml_file.scene:
assert isinstance(scene_object, SceneObject)
for o in scene_object.output:
assert isinstance(o, ObjectElement)
if o.id == obj:
# TODO define type/Format of this output
return self, ExporterOutputVariable(obj, physical=msml.sortdef.VTK)
[docs] def gather_output(self):
"""finds all variables that is provided by the exporter
:param msmlfile: msml.model.base.MSMLFile
:return: list of MSMLVariables
"""
self._output = {}
for obj in self._msml_file.scene:
for out in obj.output:
tag = out.attributes['__tag__']
id = out.attributes['id']
fmt = object
typ = object
if self._output_types_of_elements and \
tag in self._output_types_of_elements:
typ, fmt = self._output_types_of_elements[tag]
v = ExporterOutputVariable(id, fmt, typ)
self._output[id] = v
[docs] def link(self):
from msml.model.base import link_algorithm
slots = dict(self._input)
self.arguments = link_algorithm(self._msml_file, self._attributes, self, slots)
def _match_features(self):
needed = get_needed_features(self._msml_file)
match = needed <= self.features
if match:
log.info("every features is supported by current exporter")
else:
log.error("some features are not supported by exporter")
log.error("-- msml_file: %s", needed)
log.error("-- supported: %s", self.features)
log.error("-- not matched: %s", needed - self.features)
return match
[docs] def init_exec(self, executer):
"""
initialization by the executor, sets memory and executor member
:param executer: msml.run.Executer
:return:
"""
self._executer = executer
self._memory = self._executer._memory
""":type msml.run.memory.Memory"""
[docs] def render(self):
"""
Builds the File (XML e.g) for the external tool
"""
pass
[docs] def execute(self):
"should execute the external tool and set the memory"
pass
[docs] def evaluate_node(self, expression):
if ((expression[0:2] == '${') & (expression[-1] == '}') ):
# in this case, get value from workflow
data = self._memory._internal
for seg in expression[2:-1].split("."):
data = data[seg]
return data
else:
return expression
# every reference should be full, commented out from weigl
# if isinstance(resultNode, basestring):
# resultExpression = resultNode
# else:
# resultExpression = resultNode[resultNode.keys()[0]]
[docs] def get_value_from_memory(self, reference, parameter=None):
"""
:param reference:
:return:
"""
if isinstance(reference, str):
return self.get_value_from_memory(self.arguments[reference])
elif isinstance(reference, Mesh):
return self.get_value_from_memory(self.get_input_mesh_name(reference))
elif isinstance(reference, MaterialRegion):
return self.get_value_from_memory(self.get_input_material_name(reference))
elif isinstance(reference, IndexGroup):
return self.get_value_from_memory(self.get_input_set_name(reference))
elif isinstance(reference, ObjectElement):
return self.get_value_from_memory(self.get_input_objectelement_name(reference, parameter))
elif isinstance(reference, Reference):
return self._memory.lookup(reference)
else:
raise MSMLException("no suitable reference was given (%s)" % reference)
@property
def datamodel(self):
if not self._datamodel:
self._datamodel = self.generate_data_model()
return self._datamodel
[docs] def generate_data_model(self):
def _scene(sceneobject):
"""
:param scene: an object from the scene
:type scene: msml.model.base.SceneObject
:return: a scene object with references solved
"""
ns = SceneObject(
sceneobject.id,
_mesh(sceneobject.mesh),
_scene_sets(sceneobject.sets),
map(_region, sceneobject.material),
map(_constraint, sceneobject.constraints)
)
return ns
def _scene_sets(sets):
assert isinstance(sets, SceneObjectSets)
def _resolve(indexgroup):
assert isinstance(indexgroup, IndexGroup)
ig = IndexGroup(indexgroup.id, self.get_value_from_memory(indexgroup))
return ig
_map_resolve = lambda seq: map(_resolve, seq)
ns = SceneObjectSets(
_map_resolve(sets.elements),
_map_resolve(sets.nodes),
_map_resolve(sets.surfaces),
)
return ns
def _mesh(mesh):
assert isinstance(mesh, Mesh)
return Mesh(mesh.id, mesh.id, self.get_value_from_memory(mesh))
def _object_element(objectelement):
assert isinstance(objectelement, ObjectElement)
attrib = objectelement.attributes
objectelement.meta
values = {k: self.get_value_from_memory(objectelement, k) for k in objectelement.meta.parameters}
return ObjectElement(values, objectelement.meta)
def _region(materialregion):
assert isinstance(materialregion, MaterialRegion)
return MaterialRegion(materialregion.id, self.get_value_from_memory(materialregion),
map(_object_element, materialregion))
def _constraint(objectconstraints):
assert isinstance(objectconstraints, ObjectConstraints)
oc = ObjectConstraints(objectconstraints.name, objectconstraints.for_step)
oc.constraints = map(_object_element, objectconstraints.constraints)
return oc
return map(_scene, self._msml_file.scene)
class XMLExporter(Exporter): pass