Skip to content

IsosurfaceSampling

vtk-examples/PythonicAPI/Visualization/IsosurfaceSampling

Description

This example illustrates how to create an isosurface and create point data on that isosurface that is sampled from another dataset. This example creates an isosurface of a sphere and then uses the vtkProbeFilter to compute point data from a sampled cylinder.

Note

All point data is sampled, even the normals. This example restores the original isosurface normals after the probe. The example has one optional command line argument that controls the sample resolution of the sphere and cylinder. The default is 50.

Other languages

See (Cxx), (Python)

Question

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

Code

IsosurfaceSampling.py

#!/usr/bin/env python3

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.util.execution_model import select_ports
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonDataModel import (
    vtkCylinder,
    vtkSphere
)
from vtkmodules.vtkFiltersCore import (
    vtkFlyingEdges3D,
    vtkMarchingCubes,
    vtkProbeFilter
)
from vtkmodules.vtkImagingHybrid import vtkSampleFunction
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)


def main():
    colors = vtkNamedColors()

    sample_resolution, use_flying_edges = get_program_parameters()

    radius = 1.0
    # Create a sampled sphere
    implicit_sphere = vtkSphere(radius=radius)

    x_min = -radius * 2.0
    x_max = radius * 2.0
    sampled_sphere = vtkSampleFunction(implicit_function=implicit_sphere,
                                       sample_dimensions=(sample_resolution, sample_resolution, sample_resolution),
                                       model_bounds=(x_min, x_max, x_min, x_max, x_min, x_max))

    if use_flying_edges:
        iso_sphere = vtkFlyingEdges3D()
    else:
        iso_sphere = vtkMarchingCubes()
    iso_sphere.SetValue(0, 1.0)
    sampled_sphere >> iso_sphere

    # Create a sampled cylinder
    implicit_cylinder = vtkCylinder(radius=radius / 2.0)
    sampled_cylinder = vtkSampleFunction(implicit_function=implicit_cylinder,
                                         sample_dimensions=(sample_resolution, sample_resolution, sample_resolution),
                                         model_bounds=(x_min, x_max, x_min, x_max, x_min, x_max))

    # Probe cylinder with the sphere isosurface.
    probe_cylinder = vtkProbeFilter()
    iso_sphere >> select_ports(0, probe_cylinder)
    sampled_cylinder >> select_ports(1, probe_cylinder)
    probe_cylinder.update()

    # Restore the original normals.
    probe_cylinder.output.point_data.SetNormals(iso_sphere.output.point_data.normals)

    sr = probe_cylinder.output.scalar_range
    print(f'Scalar range: {sr[0]:6.3f}, {sr[1]:6.3f}')

    # Create a mapper and actor
    map_sphere = vtkPolyDataMapper(scalar_range=sr)
    probe_cylinder >> map_sphere

    sphere = vtkActor(mapper=map_sphere)

    # Visualize
    renderer = vtkRenderer(background=colors.GetColor3d('AliceBlue'))
    render_window = vtkRenderWindow(window_name='IsosurfaceSampling')
    render_window.AddRenderer(renderer)

    render_window_interactor = vtkRenderWindowInteractor()
    render_window_interactor.render_window = render_window

    renderer.AddActor(sphere)

    render_window.Render()
    render_window_interactor.Start()


def get_program_parameters():
    import argparse
    description = 'Create an isosurface and create point data on that isosurface that is sampled from another dataset.'
    epilogue = '''
    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('-r', '--resolution', type=int, default=50,
                        help='The sample resolution of the sphere and cylinder')
    parser.add_argument('-m', '--marching_cubes', action='store_false',
                        help='Use Marching Cubes instead of Flying Edges.')
    args = parser.parse_args()
    return args.resolution, args.resolution


if __name__ == '__main__':
    main()