Skip to content

SaveSceneToFieldData

web-test/PythonicAPI/Utilities/SaveSceneToFieldData

Description

This example saves a vtkCamera's parameters in the vtkFieldData of a vkDataSet.

To see how the scene is saved and restored,

  1. Interact with the scene. Press the e key to exit the first iteractor. The current state of the scene's vtkCamera will be saved in the vtkDataSet's vtkFieldData.

  2. Interact with the scene again. Press the e key to exit the second interactor. The scene will be restored to the previous state.

  3. Press the e key to exit the example.

Info

This example uses snippets.

Other languages

See (Cxx), (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

SaveSceneToFieldData.py

#!/usr/bin/env python3

from pathlib import Path

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkStringArray
from vtkmodules.vtkIOGeometry import (
    vtkBYUReader,
    vtkOBJReader,
    vtkSTLReader
)
from vtkmodules.vtkIOLegacy import vtkPolyDataReader
from vtkmodules.vtkIOPLY import vtkPLYReader
from vtkmodules.vtkIOXML import vtkXMLPolyDataReader
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)


def main():
    pd_fn = get_program_parameters()

    colors = vtkNamedColors()

    poly_data = read_poly_data(pd_fn)

    mapper = vtkPolyDataMapper()
    poly_data >> mapper

    actor = vtkActor(mapper=mapper)
    actor.property.diffuse_color = colors.GetColor3d('Crimson')
    actor.property.specular = 0.6
    actor.property.specular_power = 30

    renderer = vtkRenderer(background=colors.GetColor3d('Silver'))
    render_window = vtkRenderWindow(window_name='SaveSceneToFieldData')
    render_window.AddRenderer(renderer)

    render_window_interactor = vtkRenderWindowInteractor()
    render_window_interactor.render_window = render_window

    renderer.AddActor(actor)

    # Interact to change the camera.
    render_window.Render()
    render_window_interactor.Start()

    # After the interaction is done, save the scene.
    save_scene_to_field_data(poly_data, actor, renderer.active_camera)
    render_window.Render()
    render_window_interactor.Start()

    # After interaction , restore the scene.
    restore_scene_from_field_data(poly_data, actor, renderer.active_camera)
    render_window.Render()
    render_window_interactor.Start()


def get_program_parameters():
    import argparse
    description = 'Saving a scene to field data.'
    epilogue = '''
    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('data_file', help='A polydata file e.g. Armadillo.ply.')
    args = parser.parse_args()
    return args.data_file


def read_poly_data(file_name):
    if not file_name:
        print(f'No file name.')
        return None

    valid_suffixes = ['.g', '.obj', '.stl', '.ply', '.vtk', '.vtp']
    path = Path(file_name)
    ext = None
    if path.suffix:
        ext = path.suffix.lower()
    if path.suffix not in valid_suffixes:
        print(f'No reader for this file suffix: {ext}')
        return None

    reader = None
    if ext == '.ply':
        reader = vtkPLYReader(file_name=file_name)
    elif ext == '.vtp':
        reader = vtkXMLPolyDataReader(file_name=file_name)
    elif ext == '.obj':
        reader = vtkOBJReader(file_name=file_name)
    elif ext == '.stl':
        reader = vtkSTLReader(file_name=file_name)
    elif ext == '.vtk':
        reader = vtkPolyDataReader(file_name=file_name)
    elif ext == '.g':
        reader = vtkBYUReader(file_name=file_name)

    if reader:
        reader.update()
        poly_data = reader.output
        return poly_data
    else:
        return None


def save_scene_to_field_data(data, actor, camera):
    # Actor
    #   Position, orientation, origin, scale, usrmatrix, usertransform
    # Camera
    #   FocalPoint, Position, ViewUp, ViewAngle, ClippingRange

    fp_format = '{0:.6f}'
    res = dict()
    res['Camera:FocalPoint'] = ', '.join(fp_format.format(n) for n in camera.GetFocalPoint())
    res['Camera:Position'] = ', '.join(fp_format.format(n) for n in camera.GetPosition())
    res['Camera:ViewUp'] = ', '.join(fp_format.format(n) for n in camera.GetViewUp())
    res['Camera:ViewAngle'] = fp_format.format(camera.GetViewAngle())
    res['Camera:ClippingRange'] = ', '.join(fp_format.format(n) for n in camera.GetClippingRange())
    buffer = ''
    for k, v in res.items():
        buffer += k + ' ' + v + '\n'
    camera_array = vtkStringArray(name='Camera')
    # SetNumberOfValues() actually is a function that returns True or False.
    camera_array.SetNumberOfValues(1)
    # This has to occur after SetNumberOfValues().
    camera_array.value = (0, buffer)
    data.field_data.AddArray(camera_array)


def restore_scene_from_field_data(data, actor, camera):
    import re

    # Some regular expressions.

    re_cp = re.compile(r'^Camera:Position')
    re_cfp = re.compile(r'^Camera:FocalPoint')
    re_cvu = re.compile(r'^Camera:ViewUp')
    re_cva = re.compile(r'^Camera:ViewAngle')
    re_ccr = re.compile(r'^Camera:ClippingRange')
    keys = [re_cp, re_cfp, re_cvu, re_cva, re_ccr]

    # float_number = re.compile(r'[^0-9.\-]*([0-9e.\-]*[^,])[^0-9.\-]*([0-9e.\-]*[^,])[^0-9.\-]*([0-9e.\-]*[^,])')
    # float_scalar = re.compile(r'[^0-9.\-]*([0-9.\-e]*[^,])')

    buffer = data.GetFieldData().GetAbstractArray('Camera').GetValue(0).split('\n')
    res = dict()
    for line in buffer:
        if not line.strip():
            continue
        line = line.strip().replace(',', '').split()
        for i in keys:
            m = re.match(i, line[0])
            if m:
                k = m.group(0)
                if m:
                    #  Convert the rest of the line to floats.
                    v = list(map(lambda x: float(x), line[1:]))
                    if len(v) == 1:
                        res[k] = v[0]
                    else:
                        res[k] = v
    for k, v in res.items():
        if re.match(re_cp, k):
            camera.position = v
        elif re.match(re_cfp, k):
            camera.focal_point = v
        elif re.match(re_cvu, k):
            camera.view_up = v
        elif re.match(re_cva, k):
            camera.view_angle = v
        elif re.match(re_ccr, k):
            camera.clipping_range = v


if __name__ == '__main__':
    main()