101 lines
3.2 KiB
Python
101 lines
3.2 KiB
Python
"""Contains the BackgroundRenderer class."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
import pyvista
|
|
from pyvista._deprecate_positional_args import _deprecate_positional_args
|
|
|
|
from .renderer import Renderer
|
|
|
|
|
|
class BackgroundRenderer(Renderer):
|
|
"""BackgroundRenderer for visualizing a background image.
|
|
|
|
Parameters
|
|
----------
|
|
parent : Renderer
|
|
The parent renderer for the background renderer.
|
|
image_path : str
|
|
Path to the image to use as a background.
|
|
scale : float, default: 1
|
|
Scaling factor for the background image.
|
|
view_port : tuple[float], optional
|
|
Viewport for the background renderer.
|
|
|
|
"""
|
|
|
|
@_deprecate_positional_args(allowed=['parent', 'image_path'])
|
|
def __init__( # noqa: PLR0917
|
|
self, parent, image_path, scale=1, view_port=None
|
|
):
|
|
"""Initialize BackgroundRenderer with an image."""
|
|
# avoiding circular import
|
|
from . import _vtk # noqa: PLC0415
|
|
|
|
# read the image first as we don't need to create a render if
|
|
# the image path is invalid
|
|
image_data = pyvista.read(image_path)
|
|
|
|
super().__init__(parent, border=False)
|
|
self.SetLayer(0)
|
|
self.InteractiveOff()
|
|
self.SetBackground(self.parent.renderer.GetBackground())
|
|
self._scale = scale
|
|
self._modified_observer = None
|
|
self._prior_window_size = None
|
|
if view_port is not None:
|
|
self.viewport = view_port
|
|
|
|
# create image actor
|
|
image_actor = _vtk.vtkImageActor()
|
|
image_actor.SetInputData(image_data)
|
|
self.add_actor(image_actor, name='background')
|
|
self.camera.enable_parallel_projection()
|
|
self.reset_camera() # necessary to get first render
|
|
self.resize()
|
|
|
|
def resize(self, *args): # noqa: ARG002
|
|
"""Resize a background renderer.
|
|
|
|
Parameters
|
|
----------
|
|
*args : tuple
|
|
Ignored arguments.
|
|
|
|
"""
|
|
if self.parent is None: # when deleted
|
|
return
|
|
if self.parent.render_window is None: # BasePlotter
|
|
return
|
|
|
|
if self._prior_window_size != self.parent.window_size:
|
|
self._prior_window_size = self.parent.window_size
|
|
|
|
actor = self._actors['background']
|
|
image_data = actor.GetInput()
|
|
origin = image_data.GetOrigin()
|
|
extent = image_data.GetExtent()
|
|
spacing = image_data.GetSpacing()
|
|
xc = origin[0] + 0.5 * (extent[0] + extent[1]) * spacing[0]
|
|
yc = origin[1] + 0.5 * (extent[2] + extent[3]) * spacing[1]
|
|
yd = (extent[3] - extent[2] + 1) * spacing[1]
|
|
dist = self.camera.distance
|
|
|
|
# make the longest dimensions match the plotting window
|
|
img_dim = np.array(image_data.dimensions[:2])
|
|
self.camera._focus = np.array([xc, yc, 0.0])
|
|
self.camera.position = np.array([xc, yc, dist])
|
|
|
|
ratio = img_dim / np.array(self.parent.window_size)
|
|
scale_value = 1
|
|
if ratio.max() > 1:
|
|
# images are not scaled if larger than the window
|
|
scale_value = ratio.max()
|
|
|
|
if self._scale is not None:
|
|
scale_value /= self._scale
|
|
|
|
self.camera.parallel_scale = 0.5 * yd / self._scale
|