File: background_renderer.py

package info (click to toggle)
python-pyvista 0.44.1-11
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 159,804 kB
  • sloc: python: 72,164; sh: 118; makefile: 68
file content (96 lines) | stat: -rw-r--r-- 3,054 bytes parent folder | download
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