1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
"""Contains the BackgroundRenderer class."""
from __future__ import annotations
import numpy as np
import pyvista
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.
"""
def __init__(self, parent, image_path, scale=1, view_port=None):
"""Initialize BackgroundRenderer with an image."""
# avoiding circular import
from . import _vtk
# 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):
"""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
|