Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] support mixed 2D / 3D rendering #839

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion napari/_qt/qt_dims.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def __init__(self, dims: Dims, parent=None):
self.dims.events.range.connect(lambda ev: self._update_range(ev.axis))
self.dims.events.ndisplay.connect(self._update_display)
self.dims.events.order.connect(self._update_display)
self.dims.events.embedded.connect(self._update_display)

@property
def nsliders(self):
Expand Down Expand Up @@ -137,7 +138,7 @@ def _update_display(self, event=None):
"""
widgets = reversed(list(enumerate(self.slider_widgets)))
for (axis, widget) in widgets:
if axis in self.dims.displayed:
if axis in self.dims.displayed and axis != self.dims.sliced:
# Displayed dimensions correspond to non displayed sliders
self._displayed_sliders[axis] = False
self.last_used = None
Expand Down
10 changes: 8 additions & 2 deletions napari/_vispy/vispy_base_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,16 @@ def _on_scale_change(self):
self.layer.position = self._transform_position(self._position)

def _on_translate_change(self):
self.translate = [
self.layer.translate[d] + self.layer.translate_grid[d]
translate = [
self.layer.translate[d]
+ self.layer._translate_view[d]
+ self.layer.translate_grid[d]
for d in self.layer.dims.displayed[::-1]
]
d = self.layer.dims.sliced
if d is not None and len(translate) == 2:
translate = translate + [self.layer._translate_view[d]]
self.translate = translate
self.layer.position = self._transform_position(self._position)

def _transform_position(self, position):
Expand Down
9 changes: 0 additions & 9 deletions napari/_vispy/vispy_image_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,6 @@ def _on_scale_change(self):
self.layer.top_left = self.find_top_left()
self.layer.position = self._transform_position(self._position)

def _on_translate_change(self):
self.translate = [
self.layer.translate[d]
+ self.layer._translate_view[d]
+ self.layer.translate_grid[d]
for d in self.layer.dims.displayed[::-1]
]
self.layer.position = self._transform_position(self._position)

def compute_data_level(self, size):
"""Computed what level of the pyramid should be viewed given the
current size of the requested field of view.
Expand Down
33 changes: 32 additions & 1 deletion napari/components/dims.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,15 @@ class Dims:
Order of only displayed dimensions.
"""

def __init__(self, ndim=None, *, ndisplay=2, order=None, axis_labels=None):
def __init__(
self,
ndim=None,
*,
ndisplay=2,
order=None,
embedded=False,
axis_labels=None,
):
super().__init__()

# Events:
Expand All @@ -64,6 +72,7 @@ def __init__(self, ndim=None, *, ndisplay=2, order=None, axis_labels=None):
axis_labels=None,
ndim=None,
ndisplay=None,
embedded=None,
order=None,
range=None,
camera=None,
Expand All @@ -76,6 +85,7 @@ def __init__(self, ndim=None, *, ndisplay=2, order=None, axis_labels=None):
self._axis_labels = []
self.clip = True
self._ndisplay = 2 if ndisplay is None else ndisplay
self._embedded = embedded

if ndim is None and order is None and axis_labels is None:
ndim = self._ndisplay
Expand Down Expand Up @@ -296,6 +306,19 @@ def ndisplay(self, ndisplay):
self.events.ndisplay()
self.events.camera()

@property
def embedded(self):
"""Bool: Whether 2D display is embedded in 3D rendering."""
return self._embedded

@embedded.setter
def embedded(self, embedded):
if self._embedded == embedded:
return

self._embedded = embedded
self.events.embedded()

@property
def displayed(self):
"""Tuple: Dimensions that are displayed."""
Expand All @@ -306,6 +329,14 @@ def not_displayed(self):
"""Tuple: Dimensions that are not displayed."""
return self.order[: -self.ndisplay]

@property
def sliced(self):
"""int: Dimension that is sliced if embedded."""
if self.embedded and self.ndim >= 3:
return self.order[-3]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will need switching to a variable rather than hardcoding

else:
return None

@property
def displayed_order(self):
"""Tuple: Order of only displayed dimensions."""
Expand Down
67 changes: 62 additions & 5 deletions napari/components/viewer_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,16 @@ def __init__(
self.theme = 'dark'

self.dims.events.camera.connect(lambda e: self.reset_view())
self.dims.events.ndisplay.connect(lambda e: self._update_layers())
self.dims.events.order.connect(lambda e: self._update_layers())
self.dims.events.axis.connect(lambda e: self._update_layers())
self.dims.events.ndisplay.connect(
lambda e: self._update_layer_dims_ndisplay()
)
self.dims.events.order.connect(
lambda e: self._update_layer_dims_order()
)
self.dims.events.embedded.connect(
lambda e: self._update_layer_dims_embedded()
)
self.dims.events.axis.connect(lambda e: self._update_layers_dims())
self.layers.events.added.connect(self._on_layers_change)
self.layers.events.removed.connect(self._on_layers_change)
self.layers.events.added.connect(self._update_active_layer)
Expand Down Expand Up @@ -1003,8 +1010,8 @@ def _new_labels(self):
empty_labels = np.zeros(dims, dtype=int)
self.add_labels(empty_labels)

def _update_layers(self, layers=None):
"""Updates the contained layers.
def _update_layer_dims_order(self, layers=None):
"""Updates the contained layers dims order.

Parameters
----------
Expand All @@ -1027,14 +1034,64 @@ def _update_layers(self, layers=None):
else:
order = list(order[order >= offset] - offset)
layer.dims.order = order

def _update_layer_dims_ndisplay(self, layers=None):
"""Updates the contained layers dims ndisplay.

Parameters
----------
layers : list of napari.layers.Layer, optional
List of layers to update. If none provided updates all.
"""
layers = layers or self.layers

for layer in layers:
layer.dims.ndisplay = self.dims.ndisplay

def _update_layer_dims_embedded(self, layers=None):
"""Updates the contained layers dims embedded status.

Parameters
----------
layers : list of napari.layers.Layer, optional
List of layers to update. If none provided updates all.
"""
layers = layers or self.layers

for layer in layers:
layer.dims.embedded = self.dims.embedded

def _update_layers_dims(self, layers=None):
"""Updates the contained layers dims points.

Parameters
----------
layers : list of napari.layers.Layer, optional
List of layers to update. If none provided updates all.
"""
layers = layers or self.layers

for layer in layers:
# Update the point values of the layers for the dimensions that
# the layer has
offset = self.dims.ndim - layer.dims.ndim
for axis in range(layer.dims.ndim):
point = self.dims.point[axis + offset]
layer.dims.set_point(axis, point)

def _update_layers(self, layers=None):
"""Updates the contained layers dims.

Parameters
----------
layers : list of napari.layers.Layer, optional
List of layers to update. If none provided updates all.
"""
self._update_layer_dims_order(layers)
self._update_layer_dims_ndisplay(layers)
self._update_layer_dims_embedded(layers)
self._update_layers_dims(layers)

def _update_active_layer(self, event):
"""Set the active layer by iterating over the layers list and
finding the first selected layer. If multiple layers are selected the
Expand Down
11 changes: 11 additions & 0 deletions napari/layers/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def __init__(
self.dims.events.ndisplay.connect(lambda e: self._update_dims())
self.dims.events.order.connect(lambda e: self._update_dims())
self.dims.events.axis.connect(lambda e: self.refresh())
self.dims.events.axis.connect(lambda e: self._embedded_slicing())

self.mouse_move_callbacks = []
self.mouse_drag_callbacks = []
Expand Down Expand Up @@ -529,6 +530,16 @@ def cursor_size(self, cursor_size):
self.events.cursor_size(cursor_size=cursor_size)
self._cursor_size = cursor_size

def _embedded_slicing(self):
"""Translate embedded view based on slicing."""
if self.dims.sliced is None or self.dims.ndisplay == 3:
return
else:
self._translate_view[self.dims.sliced] = self.dims.point[
self.dims.sliced
]
self.events.translate()

@abstractmethod
def _set_view_slice(self):
raise NotImplementedError()
Expand Down