Skip to content

Commit

Permalink
Merge pull request #20 from enthought/refactor/volume-rendering-reorg
Browse files Browse the repository at this point in the history
Break up the volume renderer code
  • Loading branch information
tonysyu committed Oct 6, 2014
2 parents d1a8477 + 567a4e3 commit 0f96e2e
Show file tree
Hide file tree
Showing 12 changed files with 404 additions and 280 deletions.
24 changes: 12 additions & 12 deletions ensemble/volren/tests/test_volume_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,46 @@
from traits_enaml.testing.enaml_test_assistant import EnamlTestAssistant

from ensemble.volren.volume_data import VolumeData
from ensemble.volren.volume_renderer import VolumeRenderer
from ensemble.volren.volume_viewer import VolumeViewer


class VolumeRendererTestCase(EnamlTestAssistant, unittest.TestCase):
class VolumeViewerTestCase(EnamlTestAssistant, unittest.TestCase):

def setUp(self):

EnamlTestAssistant.setUp(self)

enaml_source = """
from enaml.widgets.api import Container
from ensemble.volren.volume_render_view import VolumeRenderView
from ensemble.volren.volume_viewer_ui import VolumeViewerContainer
enamldef MainView(Container): view:
attr renderer
attr viewer
VolumeRenderView:
renderer << view.renderer
VolumeViewerContainer:
viewer << view.viewer
"""
volume = np.random.normal(size=(32, 32, 32))
volume = (255*(volume-volume.min())/volume.ptp()).astype(np.uint8)
volume_data = VolumeData(data=volume)
self.renderer = VolumeRenderer(volume_data=volume_data)
volume_data = VolumeData(raw_data=volume)
self.viewer = VolumeViewer(volume_data=volume_data)
self.view, _ = self.parse_and_create(enaml_source,
renderer=self.renderer)
viewer=self.viewer)

with self.event_loop():
self.view.show()

def tearDown(self):
self.view = None
self.renderer = None
self.viewer = None
EnamlTestAssistant.tearDown(self)

def test_renderer_initialized(self):
self.assertTrue(self.renderer.volume is not None)
self.assertTrue(self.viewer.volume_renderer.volume is not None)

def test_renderer_screenshot(self):
image_array = self.renderer.screenshot()
image_array = self.viewer.screenshot()
self.assertTrue(image_array.ndim == 3)
self.assertTrue(image_array.shape[-1] == 3)

Expand Down
61 changes: 61 additions & 0 deletions ensemble/volren/volume_axes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from traits.api import Bool, Float, Tuple
from tvtk.api import tvtk

from .volume_scene_member import ABCVolumeSceneMember

# Convenience for the trait definitions below
FloatPair = Tuple(Float, Float)


class VolumeAxes(ABCVolumeSceneMember):
""" An object which builds a CubeAxesActor for a scene containing a Volume.
"""

# If True, show the minor tick marks on the CubeAxesActor
show_axis_minor_ticks = Bool(False)

# What are the physical value ranges for each axis?
visible_axis_ranges = Tuple(FloatPair, FloatPair, FloatPair)

# Which axes should have a scale shown?
visible_axis_scales = Tuple(Bool, Bool, Bool)

#--------------------------------------------------------------------------
# ABCVolumeSceneMember interface
#--------------------------------------------------------------------------

def add_actors_to_scene(self, scene_model, volume_actor):

# Some axes with ticks
if any(self.visible_axis_scales):
bounds = volume_actor.bounds
x_vis, y_vis, z_vis = self.visible_axis_scales
x_range, y_range, z_range = self.visible_axis_ranges
cube_axes = tvtk.CubeAxesActor(
bounds=bounds,
camera=scene_model.camera,
tick_location='outside',
x_title='', x_units='',
y_title='', y_units='',
z_title='', z_units='',
x_axis_visibility=x_vis,
y_axis_visibility=y_vis,
z_axis_visibility=z_vis,
x_axis_range=x_range,
y_axis_range=y_range,
z_axis_range=z_range,
x_axis_minor_tick_visibility=self.show_axis_minor_ticks,
y_axis_minor_tick_visibility=self.show_axis_minor_ticks,
z_axis_minor_tick_visibility=self.show_axis_minor_ticks,
)
scene_model.renderer.add_actor(cube_axes)

#--------------------------------------------------------------------------
# Default values
#--------------------------------------------------------------------------

def _visible_axis_ranges_default(self):
return ((0.0, 1.0), (0.0, 1.0), (0.0, 1.0))

def _visible_axis_scales_default(self):
return (False, False, False)
22 changes: 22 additions & 0 deletions ensemble/volren/volume_bounding_box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from tvtk.api import tvtk

from .volume_scene_member import ABCVolumeSceneMember


class VolumeBoundingBox(ABCVolumeSceneMember):
""" An object which builds an bounding box actor for a scene containing a
Volume.
"""

#--------------------------------------------------------------------------
# ABCVolumeSceneMember interface
#--------------------------------------------------------------------------

def add_actors_to_scene(self, scene_model, volume_actor):

# An outline of the bounds of the Volume actor's data
outline = tvtk.OutlineFilter(input=volume_actor.mapper.input)
outline_mapper = tvtk.PolyDataMapper(input=outline.output)
outline_actor = tvtk.Actor(mapper=outline_mapper)
outline_actor.property.opacity = 0.3
scene_model.renderer.add_actor(outline_actor)
18 changes: 9 additions & 9 deletions ensemble/volren/volume_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ class VolumeData(HasTraits):
"""

# The data itself.
data = Property(Array(shape=(None, None, None)))
raw_data = Property(Array(shape=(None, None, None)))

# The data as a fortran array
_data = Array(shape=(None, None, None))
_raw_data = Array(shape=(None, None, None))

# The bounds of the volume
bounds = Tuple(Float, Float, Float)
Expand All @@ -27,16 +27,16 @@ class VolumeData(HasTraits):
resampled_image_data = Any()

def _bounds_default(self):
return tuple(np.array(self.spacing) * np.array(self.data.shape))
return tuple(np.array(self.spacing) * np.array(self.raw_data.shape))

def _spacing_default(self):
return (1.0, 1.0, 1.0)

def _image_data_default(self):
image_data = tvtk.ImageData()
image_data.spacing = self.spacing
image_data.dimensions = self.data.shape
image_data.point_data.scalars = self.data.ravel('F')
image_data.dimensions = self.raw_data.shape
image_data.point_data.scalars = self.raw_data.ravel('F')
# The point data scalars need a name for some Mayavi operations.
image_data.point_data.scalars.name = 'VolumeData'

Expand All @@ -58,8 +58,8 @@ def _resampled_image_data_default(self):
result.point_data.scalars.name = 'VolumeData'
return reslicer.output

def _get_data(self):
return self._data
def _get_raw_data(self):
return self._raw_data

def _set_data(self, value):
self._data = np.asfortranarray(value)
def _set_raw_data(self, value):
self._raw_data = np.asfortranarray(value)
45 changes: 0 additions & 45 deletions ensemble/volren/volume_render_view.enaml

This file was deleted.

0 comments on commit 0f96e2e

Please sign in to comment.