diff --git a/src/PythonicAPI.md b/src/PythonicAPI.md index 116e87d58abe65d1223f68aef03e0c33a30f9a98..57018e166021b6372fbc5ffd4c4c8a6ac158cd72 100644 --- a/src/PythonicAPI.md +++ b/src/PythonicAPI.md @@ -168,6 +168,8 @@ This Python script, [SelectExamples](../PythonicAPI/Utilities/SelectExamples), w | -------------- | ------------- | ------- | [AlignTwoPolyDatas](/PythonicAPI/PolyData/AlignTwoPolyDatas) | Align two vtkPolyData's. [BooleanPolyDataFilters](/PythonicAPI/PolyData/BooleanPolyDataFilters) | This example performs a boolean operation (intersection, union or difference) of two PolyData using either a vtkBooleanOperationPolyDataFilter or a vtkLoopBooleanPolyDataFilter +[Bottle](/PythonicAPI/Modelling/Bottle) | Model a rotationally symmetric object. +[CappedSphere](/PythonicAPI/Modelling/CappedSphere) | Rotate an arc to create a capped sphere. [CellsInsideObject](/PythonicAPI/PolyData/CellsInsideObject) | Extract cells inside a closed surface. [ConnectivityFilter](/PythonicAPI/Filtering/ConnectivityFilter) | Color any dataset type based on connectivity. [Curvatures](/PythonicAPI/PolyData/Curvatures) | Compute Gaussian, and Mean Curvatures. @@ -186,6 +188,7 @@ This Python script, [SelectExamples](../PythonicAPI/Utilities/SelectExamples), w [PolyDataToImageDataStencil](/PythonicAPI/PolyData/PolyDataToImageDataStencil) | [RuledSurfaceFilter](/PythonicAPI/PolyData/RuledSurfaceFilter) | [SmoothMeshGrid](/PythonicAPI/PolyData/SmoothMeshGrid) | Create a terrain with regularly spaced points and smooth it with ?vtkLoopSubdivisionFilter? and ?vtkButterflySubdivisionFilter?. +[Spring](/PythonicAPI/Modelling/Spring) | Rotation in combination with linear displacement and radius variation. [WarpTo](/PythonicAPI/Filtering/WarpTo) | Deform geometry by warping towards a point. [WarpVector](/PythonicAPI/PolyData/WarpVector) | This example warps/deflects a line. diff --git a/src/PythonicAPI/Modelling/Bottle.py b/src/PythonicAPI/Modelling/Bottle.py new file mode 100755 index 0000000000000000000000000000000000000000..787839c51342f3448d70de1e765d90e352f60e72 --- /dev/null +++ b/src/PythonicAPI/Modelling/Bottle.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonCore import vtkPoints +from vtkmodules.vtkCommonDataModel import ( + vtkCellArray, + vtkPolyData +) +from vtkmodules.vtkFiltersCore import ( + vtkStripper, + vtkTubeFilter +) +from vtkmodules.vtkFiltersModeling import vtkRotationalExtrusionFilter +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def main(): + colors = vtkNamedColors() + + # Create the RenderWindow, Renderer and Interactor. + renderer = vtkRenderer(background=colors.GetColor3d('Burlywood')) + ren_win = vtkRenderWindow(size=(640, 480), window_name='Bottle') + ren_win.AddRenderer(renderer) + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + # Create the bottle profile. + points = vtkPoints() + points.InsertPoint(0, 0.01, 0.0, 0.0) + points.InsertPoint(1, 1.5, 0.0, 0.0) + points.InsertPoint(2, 1.5, 0.0, 3.5) + points.InsertPoint(3, 1.25, 0.0, 3.75) + points.InsertPoint(4, 0.75, 0.0, 4.00) + points.InsertPoint(5, 0.6, 0.0, 4.35) + points.InsertPoint(6, 0.7, 0.0, 4.65) + points.InsertPoint(7, 1.0, 0.0, 4.75) + points.InsertPoint(8, 1.0, 0.0, 5.0) + points.InsertPoint(9, 0.2, 0.0, 5.0) + + lines = vtkCellArray() + lines.InsertNextCell(10) # The number of points. + for i in range(0, 10): + lines.InsertCellPoint(i) + + profile = vtkPolyData(points=points, lines=lines) + + # Extrude the profile to make the bottle. + extrude = vtkRotationalExtrusionFilter(input_data=profile, resolution=60) + + mapper = vtkPolyDataMapper() + extrude >> mapper + + bottle = vtkActor(mapper=mapper) + bottle.property.color = colors.GetColor3d('Mint') + + # Display the profile. + stripper = vtkStripper(input_data=profile) + + tubes = vtkTubeFilter(number_of_sides=11, radius=0.05) + + profile_mapper = vtkPolyDataMapper() + stripper >> tubes >> profile_mapper + + profile_actor = vtkActor() + profile_actor.SetMapper(profile_mapper) + profile_actor.property.color = colors.GetColor3d('Tomato') + + # Add the actors to the renderer, set the background and size. + renderer.AddActor(bottle) + renderer.AddActor(profile_actor) + renderer.SetBackground(colors.GetColor3d('Burlywood')) + + ren_win.Render() + + renderer.active_camera.position = (1, 0, 0) + renderer.active_camera.focal_point = (0, 0, 0) + renderer.active_camera.view_up = (0, 0, 1) + renderer.ResetCamera() + renderer.active_camera.Azimuth(30) + renderer.active_camera.Elevation(30) + + # Render the image. + ren_win.Render() + iren.Start() + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/Modelling/CappedSphere.md b/src/PythonicAPI/Modelling/CappedSphere.md new file mode 100644 index 0000000000000000000000000000000000000000..f3beea299675e8c5e8573c076d2dad67ca80c844 --- /dev/null +++ b/src/PythonicAPI/Modelling/CappedSphere.md @@ -0,0 +1,26 @@ +### 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. diff --git a/src/PythonicAPI/Modelling/CappedSphere.py b/src/PythonicAPI/Modelling/CappedSphere.py new file mode 100755 index 0000000000000000000000000000000000000000..d2dca9e275eaf61fbc80e7ea29e72490b83c7aad --- /dev/null +++ b/src/PythonicAPI/Modelling/CappedSphere.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 + +import math + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonCore import vtkPoints +from vtkmodules.vtkCommonDataModel import ( + vtkCellArray, + vtkLine, + vtkPolyData +) +from vtkmodules.vtkFiltersModeling import vtkRotationalExtrusionFilter +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +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 the default settings, if you set this to 45°, + # you get a bowl with a flat bottom. + start = math.radians(90) + + pts = get_line_points(angle, step, radius, uncapped, start) + + # Setup points and lines + points = vtkPoints() + lines = vtkCellArray() + for pt in pts: + pt_id = points.InsertNextPoint(pt) + if pt_id < len(pts) - 1: + line = vtkLine() + line.GetPointIds().SetId(0, pt_id) + line.GetPointIds().SetId(1, pt_id + 1) + lines.InsertNextCell(line) + + polydata = vtkPolyData(points=points, lines=lines) + + # Extrude the profile to make the capped sphere + extrude = vtkRotationalExtrusionFilter(input_data=polydata, resolution=60) + + # Visualize + colors = vtkNamedColors() + + # To see the line. + line_mapper = vtkPolyDataMapper(input_data=polydata) + + line_actor = vtkActor(mapper=line_mapper) + line_actor.property.line_width = 4 + line_actor.property.color = colors.GetColor3d('Red') + + # To see the surface. + surface_mapper = vtkPolyDataMapper() + extrude >> surface_mapper + + surface_actor = vtkActor(mapper=surface_mapper) + surface_actor.property.color = colors.GetColor3d('Khaki') + + ren = vtkRenderer(background=colors.GetColor3d('LightSlateGray')) + ren_win = vtkRenderWindow(size=(600, 600), window_name='CappedSphere') + ren_win.AddRenderer(ren) + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + ren.AddActor(surface_actor) + if show_line: + ren.AddActor(line_actor) + + ren.ResetCamera() + if show_line: + ren.active_camera.Roll(90) + ren.active_camera.Elevation(60) + + ren.ResetCameraClippingRange() + + ren_win.Render() + iren.Start() + + +def get_line_points(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() diff --git a/src/PythonicAPI/Modelling/Spring.py b/src/PythonicAPI/Modelling/Spring.py new file mode 100755 index 0000000000000000000000000000000000000000..c4eaefded2dbf9190b3e466e46afc2a4d1e91236 --- /dev/null +++ b/src/PythonicAPI/Modelling/Spring.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonCore import vtkPoints +from vtkmodules.vtkCommonDataModel import ( + vtkCellArray, + vtkPolyData +) +from vtkmodules.vtkFiltersCore import vtkPolyDataNormals +from vtkmodules.vtkFiltersModeling import vtkRotationalExtrusionFilter +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def main(): + colors = vtkNamedColors() + + # Create the RenderWindow, Renderer and Interactor. + + ren = vtkRenderer(background=colors.GetColor3d('Burlywood')) + ren_win = vtkRenderWindow(size=(640, 512), window_name='Spring') + ren_win.AddRenderer(ren) + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + # Create the spring profile (a circle). + points = vtkPoints() + points.InsertPoint(0, 1.0, 0.0, 0.0) + points.InsertPoint(1, 1.0732, 0.0, -0.1768) + points.InsertPoint(2, 1.25, 0.0, -0.25) + points.InsertPoint(3, 1.4268, 0.0, -0.1768) + points.InsertPoint(4, 1.5, 0.0, 0.00) + points.InsertPoint(5, 1.4268, 0.0, 0.1768) + points.InsertPoint(6, 1.25, 0.0, 0.25) + points.InsertPoint(7, 1.0732, 0.0, 0.1768) + + poly = vtkCellArray() + poly.InsertNextCell(8) # The number of points. + for i in range(0, 8): + poly.InsertCellPoint(i) + + profile = vtkPolyData(points=points, polys=poly) + + # Extrude the profile to make a spring. + # Note: angle=360 * 6 corresponds to six revolutions. + extrude = vtkRotationalExtrusionFilter(input_data=profile, resolution=360, + translation=6, delta_radius=1.0, + angle=360 * 6) + + normals = vtkPolyDataNormals(feature_angle=60) + + mapper = vtkPolyDataMapper() + extrude >> normals >> mapper + + spring = vtkActor(mapper=mapper) + spring.property.color = colors.GetColor3d("PowderBlue") + spring.property.diffuse = 0.7 + spring.property.specular = 0.4 + spring.property.specular_power = 20 + spring.property.backface_culling = True + + # Add the actor to the renderer, set the background and size. + ren.AddActor(spring) + + ren.ResetCamera() + ren.active_camera.Azimuth(90) + + # Render the image. + ren_win.Render() + iren.Start() + + +if __name__ == '__main__': + main() diff --git a/src/Testing/Baseline/PythonicAPI/Modelling/TestBottle.png b/src/Testing/Baseline/PythonicAPI/Modelling/TestBottle.png new file mode 100644 index 0000000000000000000000000000000000000000..e6d492a5fbb52961d93cadef6f139304aab3f1bf --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Modelling/TestBottle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bcc5918e6acbe9d0ff66090eafd9de76513cf316b7665ff08559afd184d1669 +size 30279 diff --git a/src/Testing/Baseline/PythonicAPI/Modelling/TestCappedSphere.png b/src/Testing/Baseline/PythonicAPI/Modelling/TestCappedSphere.png new file mode 100644 index 0000000000000000000000000000000000000000..79b1c2d9f7173b9e12de6cccdc8a0fe3a44a0a3d --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Modelling/TestCappedSphere.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8eb76da7971c0e685d75415c8b8339400b19fc261410301da29c2e9dd2aa350 +size 29164 diff --git a/src/Testing/Baseline/PythonicAPI/Modelling/TestSpring.png b/src/Testing/Baseline/PythonicAPI/Modelling/TestSpring.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b624c2163e180e7c0e311da710ee1ce950ca6a --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Modelling/TestSpring.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1c1eefcb00ff7eb5dfed0713df09c096db0946575fd0bca096e2e7cfb2c9b7f +size 60821