Skip to content


# CappedSphere

VTKEx/Python/Modelling/CappedSphere

### Description

Demonstrates how to create a capped sphere.

Firstly a line is created in the x-z plane corresponding to an arc from +z to -z in the +x direction in the x-z plane, the length of the arc is specified in degrees.

Then the line is extended by dropping a perpendicular to the x-axis.

The points generated are then converted to a line and passed through to the vtkRotationalExtrusionFilter to generate the resultant 3D surface.

The parameters are:

- angle - the arc length in degrees default 90° (a hemisphere)
- step -the step size of the arc in degrees, default 1°
- radius - the radius of the arc default 1

Options are provided to:

- Uncap the sphere (-u, --uncapped)
- Display the line that was rotationally extruded (-s, --show_line)

Note

The coordinate system for specifying the arc is left-handed with 0° aligned with the positive z-axis, 90° aligned with the positive x-axis.

Note

You can substitute different parametric equations for x and z in the line generating function to get other shapes.

Other languages

See (Cxx)

Question

If you have a simple question about this example contact us at VTKExProject If your question is more complex and may require extended discussion, please use the VTK Discourse Forum

### Code

CappedSphere.py

    #!/usr/bin/env python

    import math

    import vtk

    def get_program_parameters():
        import argparse
        description = 'Display a capped sphere.'
        epilogue = '''
       '''
        parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                         formatter_class=argparse.RawDescriptionHelpFormatter)
        parser.add_argument('angle', default=90, type=float, nargs='?',
                            help='The length of the arc in degrees from +z to -z in the +x direction in the x-z plane.')
        parser.add_argument('step', default=1, type=float, nargs='?', help='Step size in degrees.')
        parser.add_argument('radius', default=1, type=float, nargs='?', help='Radius of the arc.')
        parser.add_argument('-u', '--uncapped', action='store_true', help='Uncap the sphere.')
        parser.add_argument('-s', '--show_line', action='store_true',
                            help='Show the line that is rotationally extruded to make the surface.')
        args = parser.parse_args()
        return args.angle, args.step, args.radius, args.uncapped, args.show_line

    def main():
        angle, step, radius, uncapped, show_line = get_program_parameters()
        angle = math.radians(abs(angle))
        step = math.radians(abs(step))
        radius = abs(radius)
        # With default settings set this to 45 and you get a bowl with a flat bottom.
        start = math.radians(90)

        pts = get_line(angle, step, radius, uncapped, start)

        # Setup points and lines
        points = vtk.vtkPoints()
        lines = vtk.vtkCellArray()
        for pt in pts:
            pt_id = points.InsertNextPoint(pt)
            if pt_id < len(pts) - 1:
                line = vtk.vtkLine()
                line.GetPointIds().SetId(0, pt_id)
                line.GetPointIds().SetId(1, pt_id + 1)
                lines.InsertNextCell(line)

        polydata = vtk.vtkPolyData()
        polydata.SetPoints(points)
        polydata.SetLines(lines)

        # Extrude the profile to make the capped sphere
        extrude = vtk.vtkRotationalExtrusionFilter()
        extrude.SetInputData(polydata)
        extrude.SetResolution(60)

        #  Visualize
        colors = vtk.vtkNamedColors()

        # To see the line
        lineMapper = vtk.vtkPolyDataMapper()
        lineMapper.SetInputData(polydata)

        lineActor = vtk.vtkActor()
        lineActor.SetMapper(lineMapper)
        lineActor.GetProperty().SetLineWidth(4)
        lineActor.GetProperty().SetColor(colors.GetColor3d("Red"))

        # To see the surface
        surfaceMapper = vtk.vtkPolyDataMapper()
        surfaceMapper.SetInputConnection(extrude.GetOutputPort())

        surfaceActor = vtk.vtkActor()
        surfaceActor.SetMapper(surfaceMapper)
        surfaceActor.GetProperty().SetColor(colors.GetColor3d('Khaki'))

        ren = vtk.vtkRenderer()
        renWin = vtk.vtkRenderWindow()
        renWin.AddRenderer(ren)
        iren = vtk.vtkRenderWindowInteractor()
        iren.SetRenderWindow(renWin)

        ren.AddActor(surfaceActor)
        if show_line:
            ren.AddActor(lineActor)
        ren.SetBackground(colors.GetColor3d('LightSlateGray'))

        ren.ResetCamera()
        ren.GetActiveCamera().Azimuth(0)
        ren.GetActiveCamera().Elevation(60)
        ren.ResetCameraClippingRange()

        renWin.SetSize(600, 600)
        renWin.Render()
        renWin.SetWindowName('CappedSphere')
        iren.Start()

    def get_line(angle, step, radius, uncapped, start):
        """
        Get the points for a line.

        :param angle: Length of the arc in degrees.
        :param step: Step size in degrees.
        :param radius: Radius of the arc.
        :param uncapped: True if uncapped.
        :param start: Starting angle.
        :return: A vector of points.
        """
        precision = 1.0e-6
        pts = list()
        # Do the curved line
        theta = 0.0
        while theta <= angle:
            x = radius * math.cos(start - theta)
            z = radius * math.sin(theta - start)
            if x < 0:
                x = 0
                pts.append((x, 0, z))
                break
            if abs(x) < precision:
                x = 0
            if abs(z) < precision:
                z = 0
            pts.append((x, 0, z))
            theta += step

        if not uncapped:
            # Drop a perpendicular from the last point to the x-axis
            if len(pts) > 1:
                if pts[-1][0] > 0:
                    last_point = pts[-1]
                    num_pts = 10
                    interval = float(num_pts) / radius
                    for i in range(1, num_pts):
                        x = last_point[0] - i / interval
                        z = last_point[2]
                        if x < 0:
                            x = 0
                            pts.append((x, 0, z))
                            break
                        if abs(x) < precision:
                            x = 0
                        if abs(z) < precision:
                            z = 0
                        pts.append((x, 0, z))
                if pts[-1][0] > precision:
                    pts.append((0, 0, pts[-1][2]))
        return pts

    if __name__ == '__main__':
        main()