From 7ae382159ed080487566e2404afcf30b0ec6190f Mon Sep 17 00:00:00 2001 From: Andrew Maclean <andrew.amaclean@gmail.com> Date: Tue, 31 Dec 2024 16:12:00 +1100 Subject: [PATCH] Adding ImplicitAnnulusWidget --- src/Cxx.md | 1 + src/Cxx/GeometricObjects/ConesOnSphere.cxx | 2 +- src/Cxx/GeometricObjects/GoldenBallSource.cxx | 2 +- src/Cxx/GeometricObjects/SphereSource.cxx | 2 +- src/Cxx/Widgets/ImplicitAnnulusWidget.cxx | 214 +++++++++++++++++ src/PythonicAPI.md | 1 + .../GeometricObjects/ConesOnSphere.py | 2 +- .../GeometricObjects/GoldenBallSource.py | 2 +- .../GeometricObjects/SphereSource.py | 2 +- .../Widgets/ImplicitAnnulusWidget.py | 217 ++++++++++++++++++ .../Widgets/ImplicitPlaneWidget2.py | 46 ++-- .../Cxx/Widgets/TestImplicitAnnulusWidget.png | 3 + .../Widgets/TestImplicitAnnulusWidget.png | 3 + 13 files changed, 467 insertions(+), 30 deletions(-) create mode 100644 src/Cxx/Widgets/ImplicitAnnulusWidget.cxx create mode 100644 src/PythonicAPI/Widgets/ImplicitAnnulusWidget.py create mode 100644 src/Testing/Baseline/Cxx/Widgets/TestImplicitAnnulusWidget.png create mode 100644 src/Testing/Baseline/PythonicAPI/Widgets/TestImplicitAnnulusWidget.png diff --git a/src/Cxx.md b/src/Cxx.md index badd640e660..11095d51ed8 100644 --- a/src/Cxx.md +++ b/src/Cxx.md @@ -1349,6 +1349,7 @@ See [this tutorial](http://www.vtk.org/Wiki/VTK/Tutorials/3DDataTypes) for a bri [ImageTracerWidget](/Cxx/Widgets/ImageTracerWidget) | Scribble on an image. [ImageTracerWidgetInsideContour](/Cxx/Widgets/ImageTracerWidgetInsideContour) | Highlight pixels inside a non-regular region scribbled on an image. [ImageTracerWidgetNonPlanar](/Cxx/Widgets/ImageTracerWidgetNonPlanar) | Draw on a non-planar surface. +[ImplicitAnnulusWidget](/Cxx/Widgets/ImplicitAnnulusWidget) | Clip polydata with an implicit annulus. [ImplicitConeWidget](/Cxx/Widgets/ImplicitConeWidget) | An interactive implicit cone widget. [ImplicitPlaneWidget2](/Cxx/Widgets/ImplicitPlaneWidget2) | Clip polydata with an implicit plane. [LineWidget2](/Cxx/Widgets/LineWidget2) | diff --git a/src/Cxx/GeometricObjects/ConesOnSphere.cxx b/src/Cxx/GeometricObjects/ConesOnSphere.cxx index c38c9bae100..40789169b13 100644 --- a/src/Cxx/GeometricObjects/ConesOnSphere.cxx +++ b/src/Cxx/GeometricObjects/ConesOnSphere.cxx @@ -63,7 +63,7 @@ int main(int, char*[]) vtkNew<vtkRenderer> renderer; vtkNew<vtkRenderWindow> renderWindow; renderWindow->SetSize(600, 600); - renderWindow->SetWindowName("Cones on Sphere"); + renderWindow->SetWindowName("ConesOnSphere"); renderWindow->AddRenderer(renderer); vtkNew<vtkRenderWindowInteractor> renderWindowInteractor; renderWindowInteractor->SetRenderWindow(renderWindow); diff --git a/src/Cxx/GeometricObjects/GoldenBallSource.cxx b/src/Cxx/GeometricObjects/GoldenBallSource.cxx index b5f6e308048..e58a9a736db 100644 --- a/src/Cxx/GeometricObjects/GoldenBallSource.cxx +++ b/src/Cxx/GeometricObjects/GoldenBallSource.cxx @@ -43,7 +43,7 @@ int main(int, char*[]) renderer->SetBackground(colors->GetColor3d("ParaViewBkg").GetData()); vtkNew<vtkRenderWindow> renderWindow; renderWindow->SetSize(600, 600); - renderWindow->SetWindowName("Golden Ball Source"); + renderWindow->SetWindowName("GoldenBallSource"); renderWindow->AddRenderer(renderer); vtkNew<vtkRenderWindowInteractor> renderWindowInteractor; renderWindowInteractor->SetRenderWindow(renderWindow); diff --git a/src/Cxx/GeometricObjects/SphereSource.cxx b/src/Cxx/GeometricObjects/SphereSource.cxx index 8af6cda05dd..4e147928969 100644 --- a/src/Cxx/GeometricObjects/SphereSource.cxx +++ b/src/Cxx/GeometricObjects/SphereSource.cxx @@ -42,7 +42,7 @@ int main(int, char*[]) vtkNew<vtkRenderer> renderer; vtkNew<vtkRenderWindow> renderWindow; renderWindow->SetSize(600, 600); - renderWindow->SetWindowName("Sphere Source"); + renderWindow->SetWindowName("SphereSource"); renderWindow->AddRenderer(renderer); vtkNew<vtkRenderWindowInteractor> renderWindowInteractor; renderWindowInteractor->SetRenderWindow(renderWindow); diff --git a/src/Cxx/Widgets/ImplicitAnnulusWidget.cxx b/src/Cxx/Widgets/ImplicitAnnulusWidget.cxx new file mode 100644 index 00000000000..2f6da27cda8 --- /dev/null +++ b/src/Cxx/Widgets/ImplicitAnnulusWidget.cxx @@ -0,0 +1,214 @@ +#include <vtkActor.h> +#include <vtkAnnulus.h> +#include <vtkAppendPolyData.h> +#include <vtkCamera.h> +#include <vtkCameraOrientationWidget.h> +#include <vtkClipPolyData.h> +#include <vtkCommand.h> +#include <vtkConeSource.h> +#include <vtkGlyph3D.h> +#include <vtkImplicitAnnulusRepresentation.h> +#include <vtkImplicitAnnulusWidget.h> +#include <vtkInteractorStyleSwitch.h> +#include <vtkNamedColors.h> +#include <vtkNew.h> +#include <vtkPolyDataMapper.h> +#include <vtkProperty.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkSphereSource.h> +#include <vtkXMLPolyDataReader.h> + +#include <algorithm> +#include <vector> + +namespace { +// This does the actual work: updates the vtkAnnulus implicit function. +// This in turn causes the pipeline to update and clip the object. +// Callback for the interaction +class vtkTICWCallback : public vtkCommand +{ +public: + static vtkTICWCallback* New() + { + return new vtkTICWCallback; + } + + void Execute(vtkObject* caller, unsigned long, void*) override + { + vtkImplicitAnnulusWidget* annulusWidget = + reinterpret_cast<vtkImplicitAnnulusWidget*>(caller); + vtkImplicitAnnulusRepresentation* rep = + reinterpret_cast<vtkImplicitAnnulusRepresentation*>( + annulusWidget->GetRepresentation()); + rep->GetAnnulus(this->Annulus); + this->Actor->VisibilityOn(); + } + + vtkAnnulus* Annulus{nullptr}; + vtkActor* Actor{nullptr}; +}; + +vtkNew<vtkAppendPolyData> CreateMace(); + +} // namespace + +int main(int argc, char* argv[]) +{ + + vtkNew<vtkNamedColors> colors; + + vtkNew<vtkXMLPolyDataReader> reader; + + // This portion of the code clips the mace or the input from the reader with + // the vtkAnnulus implicit function. The clipped region is colored green. + vtkNew<vtkAnnulus> annulus; + vtkNew<vtkClipPolyData> clipper; + clipper->SetClipFunction(annulus); + clipper->InsideOutOn(); + + vtkSmartPointer<vtkPolyData> source; + if (argc < 2) + { + auto mace = CreateMace(); + source = mace->GetOutput(); + } + else + { + // For example: cow.vtp + reader->SetFileName(argv[1]); + reader->Update(); + source = reader->GetOutput(); + } + clipper->SetInputData(source); + auto bounds = source->GetBounds(); + + std::cout << "bounds: ("; + for (auto i = 0; i < 6; ++i) + { + if (i == 0) + { + std::cout << bounds[i]; + } + else + { + std::cout << " " << bounds[i]; + } + } + std::cout << ")" << std::endl; + + vtkNew<vtkPolyDataMapper> mapper; + mapper->SetInputData(source); + + vtkNew<vtkProperty> backFaces; + backFaces->SetDiffuseColor(colors->GetColor3d("Gold").GetData()); + + vtkNew<vtkActor> actor; + actor->SetBackfaceProperty(backFaces); + actor->SetMapper(mapper); + actor->VisibilityOn(); + + vtkNew<vtkPolyDataMapper> selectMapper; + selectMapper->SetInputConnection(clipper->GetOutputPort()); + + vtkNew<vtkActor> selectActor; + selectActor->SetMapper(selectMapper); + selectActor->GetProperty()->SetColor(colors->GetColor3d("Lime").GetData()); + selectActor->VisibilityOff(); + selectActor->SetScale(1.01, 1.01, 1.01); + + // Create the RenderWindow, Renderer and both Actors + vtkNew<vtkRenderer> renderer; + renderer->AddActor(actor); + renderer->AddActor(selectActor); + renderer->SetBackground(colors->GetColor3d("MidnightBlue").GetData()); + + vtkNew<vtkRenderWindow> renWin; + renWin->SetMultiSamples(0); + renWin->SetSize(600, 600); + renWin->SetWindowName("ImplicitAnnulusWidget"); + renWin->AddRenderer(renderer); + + vtkNew<vtkRenderWindowInteractor> iren; + renWin->SetInteractor(iren); + auto is = vtkInteractorStyleSwitch::SafeDownCast(iren->GetInteractorStyle()); + if (is) + { + is->SetCurrentStyleToTrackballCamera(); + } + + // The SetInteractor method is how 3D widgets are associated with the render + // window interactor. Internally, SetInteractor sets up a bunch of callbacks + // using the Command/Observer mechanism (AddObserver()). + vtkNew<vtkTICWCallback> myCallback; + myCallback->Annulus = annulus; + myCallback->Actor = selectActor; + + std::vector<double> radii; + for (auto i = 1; i < 6; i += 2) + { + radii.push_back((bounds[i] - bounds[i - 1]) / 2.0); + } + auto radius = *std::min_element(radii.cbegin(), radii.cend()); + + vtkNew<vtkImplicitAnnulusRepresentation> rep; + rep->SetPlaceFactor(1.25); + rep->ScaleEnabledOff(); + rep->PlaceWidget(bounds); + rep->SetInnerRadius(radius * 0.5); + rep->SetOuterRadius(radius); + std::cout << "Inner radius: " << rep->GetInnerRadius() << std::endl; + std::cout << "Outer radius: " << rep->GetOuterRadius() << std::endl; + + vtkNew<vtkImplicitAnnulusWidget> annulusWidget; + annulusWidget->SetInteractor(iren); + annulusWidget->SetRepresentation(rep); + annulusWidget->AddObserver(vtkCommand::InteractionEvent, myCallback); + annulusWidget->EnabledOn(); + + renderer->GetActiveCamera()->Azimuth(60); + renderer->GetActiveCamera()->Elevation(30); + renderer->ResetCamera(); + renderer->GetActiveCamera()->Zoom(1.0); + + vtkNew<vtkCameraOrientationWidget> cow; + cow->SetParentRenderer(renderer); + // Enable the widget. + cow->On(); + + // Render and interact. + iren->Initialize(); + renWin->Render(); + annulusWidget->On(); + + // Begin mouse interaction. + iren->Start(); + + return EXIT_SUCCESS; +} + +namespace { +vtkNew<vtkAppendPolyData> CreateMace() +{ + // Create a mace out of filters. + vtkNew<vtkSphereSource> sphere; + vtkNew<vtkConeSource> coneSource; + vtkNew<vtkGlyph3D> glyph; + glyph->SetInputConnection(sphere->GetOutputPort()); + glyph->SetSourceConnection(coneSource->GetOutputPort()); + glyph->SetVectorModeToUseNormal(); + glyph->SetScaleModeToScaleByVector(); + glyph->SetScaleFactor(0.25); + + // The sphere and spikes are appended into a single polydata. + // This just makes things simpler to manage. + vtkNew<vtkAppendPolyData> apd; + apd->AddInputConnection(glyph->GetOutputPort()); + apd->AddInputConnection(sphere->GetOutputPort()); + apd->Update(); + + return apd; +} +} // namespace diff --git a/src/PythonicAPI.md b/src/PythonicAPI.md index 47f3abe1602..e279853df00 100644 --- a/src/PythonicAPI.md +++ b/src/PythonicAPI.md @@ -702,6 +702,7 @@ See [this tutorial](http://www.vtk.org/Wiki/VTK/Tutorials/3DDataTypes) for a bri [ImagePlaneWidget](/PythonicAPI/Widgets/ImagePlaneWidget) | [ImageTracerWidgetInsideContour](/PythonicAPI/Widgets/ImageTracerWidgetInsideContour) | Highlight pixels inside a non-regular region scribbled on an image. [ImageTracerWidgetNonPlanar](/PythonicAPI/Widgets/ImageTracerWidgetNonPlanar) | Draw on a non-planar surface. +[ImplicitAnnulusWidget](/PythonicAPI/Widgets/ImplicitAnnulusWidget) | Clip polydata with an implicit annulus. [ImplicitConeWidget](/PythonicAPI/Widgets/ImplicitConeWidget) | An interactive implicit cone widget. [ImplicitPlaneWidget2](/PythonicAPI/Widgets/ImplicitPlaneWidget2) | Clip polydata with an implicit plane. [PolygonalSurfacePointPlacer](/PythonicAPI/PolyData/PolygonalSurfacePointPlacer) | Used in conjunction with vtkContourWidget to draw curves on a surface. diff --git a/src/PythonicAPI/GeometricObjects/ConesOnSphere.py b/src/PythonicAPI/GeometricObjects/ConesOnSphere.py index e94cbe88dd5..3914226f5d3 100755 --- a/src/PythonicAPI/GeometricObjects/ConesOnSphere.py +++ b/src/PythonicAPI/GeometricObjects/ConesOnSphere.py @@ -66,7 +66,7 @@ def main(): actor = vtkActor(property=actor_prop, mapper=mapper) renderer = vtkRenderer(background=colors.GetColor3d('ParaViewBkg')) - render_window = vtkRenderWindow(size=(600, 600), window_name='Cones on Sphere') + render_window = vtkRenderWindow(size=(600, 600), window_name='ConesOnSphere') render_window.AddRenderer(renderer) render_window_interactor = vtkRenderWindowInteractor() render_window_interactor.SetRenderWindow(render_window) diff --git a/src/PythonicAPI/GeometricObjects/GoldenBallSource.py b/src/PythonicAPI/GeometricObjects/GoldenBallSource.py index 67516e6f9c9..d583d81a15a 100755 --- a/src/PythonicAPI/GeometricObjects/GoldenBallSource.py +++ b/src/PythonicAPI/GeometricObjects/GoldenBallSource.py @@ -35,7 +35,7 @@ def main(): actor = vtkActor(property=actor_prop, mapper=mapper) renderer = vtkRenderer(background=colors.GetColor3d('ParaViewBkg')) - render_window = vtkRenderWindow(size=(600, 600), window_name='Golden Ball Source') + render_window = vtkRenderWindow(size=(600, 600), window_name='GoldenBallSource') render_window.AddRenderer(renderer) render_window_interactor = vtkRenderWindowInteractor() render_window_interactor.SetRenderWindow(render_window) diff --git a/src/PythonicAPI/GeometricObjects/SphereSource.py b/src/PythonicAPI/GeometricObjects/SphereSource.py index 01681a46d3f..72eeacfa5ab 100755 --- a/src/PythonicAPI/GeometricObjects/SphereSource.py +++ b/src/PythonicAPI/GeometricObjects/SphereSource.py @@ -33,7 +33,7 @@ def main(): actor = vtkActor(property=actor_prop, mapper=mapper) renderer = vtkRenderer(background=colors.GetColor3d('ParaViewBkg')) - render_window = vtkRenderWindow(size=(600, 600), window_name='Sphere Source') + render_window = vtkRenderWindow(size=(600, 600), window_name='SphereSource') render_window.AddRenderer(renderer) render_window_interactor = vtkRenderWindowInteractor() render_window_interactor.SetRenderWindow(render_window) diff --git a/src/PythonicAPI/Widgets/ImplicitAnnulusWidget.py b/src/PythonicAPI/Widgets/ImplicitAnnulusWidget.py new file mode 100644 index 00000000000..e0789fb6ce0 --- /dev/null +++ b/src/PythonicAPI/Widgets/ImplicitAnnulusWidget.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass +from pathlib import Path + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingUI +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonDataModel import vtkAnnulus +from vtkmodules.vtkFiltersCore import ( + vtkAppendPolyData, + vtkClipPolyData, + vtkGlyph3D +) +from vtkmodules.vtkFiltersSources import ( + vtkConeSource, + vtkSphereSource) +from vtkmodules.vtkIOXML import vtkXMLPolyDataReader +from vtkmodules.vtkInteractionWidgets import ( + vtkCameraOrientationWidget, + vtkImplicitAnnulusRepresentation, + vtkImplicitAnnulusWidget, +) +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, + vtkProperty, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def get_program_parameters(): + import argparse + description = 'Clip polydata with an implicit annulus.' + epilogue = ''' + By specifying a .vtp file, the example can operate on arbitrary polydata. +''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('file_name', nargs='?', default=None, help='A VTK Poly Data file e.g. cow.vtp') + + args = parser.parse_args() + return args.file_name + + +def main(fn): + colors = vtkNamedColors() + + fn = get_program_parameters() + + # This portion of the code clips the mace or the input from the reader with + # the vtkAnnulus implicit function. The clipped region is colored green. + annulus = vtkAnnulus() + clipper = vtkClipPolyData(clip_function=annulus, inside_out=True) + + if fn: + fp = Path(fn) + if not (fp.is_file() and fp.suffix == '.vtp'): + print(f'Expected an existing file name with extension .vtp\n got: {fp}') + return + + reader = vtkXMLPolyDataReader(file_name=fp) + reader >> clipper + source = reader.update().output + else: + mace = create_mace() + source = mace.output + + clipper.input_data = source + bounds = source.bounds + print(f'bounds: ({fmt_floats(bounds)})') + + # Create a mapper and actor. + mapper = vtkPolyDataMapper(input_data=source) + + back_faces = vtkProperty(diffuse_color=colors.GetColor3d('Gold')) + + actor = vtkActor(backface_property=back_faces, mapper=mapper, visibility=True) + + select_mapper = vtkPolyDataMapper() + clipper >> select_mapper + + select_actor = vtkActor(mapper=select_mapper, scale=(1.01, 1.01, 1.01), visibility=False) + select_actor.property.color = colors.GetColor3d('Lime') + + # Create the RenderWindow, Renderer and both Actors + renderer = vtkRenderer(background=colors.GetColor3d('MidnightBlue')) + renderer.AddActor(actor) + renderer.AddActor(select_actor) + ren_win = vtkRenderWindow(multi_samples=0, size=(600, 600), window_name='ImplicitAnnulusWidget') + ren_win.AddRenderer(renderer) + iren = vtkRenderWindowInteractor() + ren_win.interactor = iren + # Since we import vtkmodules.vtkInteractionStyle we can do this + # because vtkInteractorStyleSwitch is automatically imported: + iren.interactor_style.SetCurrentStyleToTrackballCamera() + + # The SetInteractor method is how 3D widgets are associated with the render + # window interactor. Internally, SetInteractor sets up a bunch of callbacks + # using the Command/Observer mechanism (AddObserver()). + my_callback = TICWCallback(annulus, select_actor) + + radii = list() + for i in range(1, 6, 2): + radii.append((bounds[i] - bounds[i - 1]) / 2.0) + radius = min(radii) + + rep = vtkImplicitAnnulusRepresentation(place_factor=1.25, scale_enabled=False, + inner_radius=radius * 0.5, outer_radius=radius) + rep.PlaceWidget(bounds) + print(f'Inner radius: {rep.inner_radius:g}') + print(f'Outer radius: {rep.outer_radius:g}') + + annulus_widget = vtkImplicitAnnulusWidget(interactor=iren, representation=rep, enabled=True) + annulus_widget.AddObserver('InteractionEvent', my_callback) + + renderer.active_camera.Azimuth(60) + renderer.active_camera.Elevation(30) + renderer.ResetCamera() + renderer.active_camera.Zoom(1.0) + + cow = vtkCameraOrientationWidget(parent_renderer=renderer) + # Enable the widget. + cow.On() + + # Render and interact. + iren.Initialize() + ren_win.Render() + annulus_widget.On() + + # Begin mouse interaction. + iren.Start() + + +class TICWCallback: + def __init__(self, annulus, select_actor): + self.annulus = annulus + self.select_actor = select_actor + + def __call__(self, caller, ev): + rep = caller.representation + rep.GetAnnulus(self.annulus) + self.select_actor.visibility = True + + +def create_mace(): + # Create a mace out of filters. + sphere = vtkSphereSource() + cone_source = vtkConeSource() + glyph = vtkGlyph3D(source_connection=cone_source.output_port, + vector_mode=Glyph3D.VectorMode.VTK_USE_NORMAL, + scale_mode=Glyph3D.ScaleMode.VTK_SCALE_BY_VECTOR, + scale_factor=0.25) + sphere >> glyph + + # The sphere and spikes are appended into a single polydata. + # This just makes things simpler to manage. + apd = vtkAppendPolyData() + (glyph, sphere) >> apd + apd.update() + return apd + + +def fmt_floats(v, w=0, d=6, pt='g'): + """ + Pretty print a list or tuple of floats. + + :param v: The list or tuple of floats. + :param w: Total width of the field. + :param d: The number of decimal places. + :param pt: The presentation type, 'f', 'g' or 'e'. + :return: A string. + """ + pt = pt.lower() + if pt not in ['f', 'g', 'e']: + pt = 'f' + return ', '.join([f'{element:{w}.{d}{pt}}' for element in v]) + + +@dataclass(frozen=True) +class Glyph3D: + @dataclass(frozen=True) + class ColorMode: + VTK_COLOR_BY_SCALE: int = 0 + VTK_COLOR_BY_SCALAR: int = 1 + VTK_COLOR_BY_VECTOR: int = 2 + + @dataclass(frozen=True) + class IndexMode: + VTK_INDEXING_OFF: int = 0 + VTK_INDEXING_BY_SCALAR: int = 1 + VTK_INDEXING_BY_VECTOR: int = 2 + + @dataclass(frozen=True) + class ScaleMode: + VTK_SCALE_BY_SCALAR: int = 0 + VTK_SCALE_BY_VECTOR: int = 1 + VTK_SCALE_BY_VECTORCOMPONENTS: int = 2 + VTK_DATA_SCALING_OFF: int = 3 + + @dataclass(frozen=True) + class VectorMode: + VTK_USE_VECTOR: int = 0 + VTK_USE_NORMAL: int = 1 + VTK_VECTOR_ROTATION_OFF: int = 2 + VTK_FOLLOW_CAMERA_DIRECTION: int = 3 + + +if __name__ == '__main__': + file_name = get_program_parameters() + main(file_name) diff --git a/src/PythonicAPI/Widgets/ImplicitPlaneWidget2.py b/src/PythonicAPI/Widgets/ImplicitPlaneWidget2.py index 43d65404b97..10dccc72e68 100755 --- a/src/PythonicAPI/Widgets/ImplicitPlaneWidget2.py +++ b/src/PythonicAPI/Widgets/ImplicitPlaneWidget2.py @@ -11,9 +11,7 @@ import vtkmodules.vtkRenderingUI from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkCommonCore import vtkCommand from vtkmodules.vtkCommonDataModel import vtkPlane -from vtkmodules.vtkFiltersCore import ( - vtkClipPolyData -) +from vtkmodules.vtkFiltersCore import vtkClipPolyData from vtkmodules.vtkFiltersSources import vtkSphereSource from vtkmodules.vtkIOXML import vtkXMLPolyDataReader from vtkmodules.vtkInteractionWidgets import ( @@ -30,21 +28,37 @@ from vtkmodules.vtkRenderingCore import ( ) +def get_program_parameters(): + import argparse + description = 'How to use the second generation ImplicitPlaneWidget2 to interactively' \ + ' define the clipping plane for a polydata.' + epilogue = ''' + If no arguments are specified, a vtkSphereSource generates the polydata. + By specifying a .vtp file, the example can operate on arbitrary polydata. +''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('file_name', nargs='?', default=None, help='A VTK Poly Data file e.g. cow.vtp') + + args = parser.parse_args() + return args.file_name + + def main(fn): colors = vtkNamedColors() sphere_source = vtkSphereSource(radius=10.0) - fp = None + fn = get_program_parameters() + + # Setup a visualization pipeline. + plane = vtkPlane() + clipper = vtkClipPolyData(clip_function=plane, inside_out=True) if fn: fp = Path(fn) if not (fp.is_file() and fp.suffix == '.vtp'): print(f'Expected an existing file name with extension .vtp\n got: {fp}') return - # Setup a visualization pipeline. - plane = vtkPlane() - clipper = vtkClipPolyData(clip_function=plane, inside_out=True) - if fp: reader = vtkXMLPolyDataReader(file_name=fp) reader >> clipper else: @@ -102,22 +116,6 @@ class IPWCallback: rep.GetPlane(self.plane) -def get_program_parameters(): - import argparse - description = 'How to use the second generation ImplicitPlaneWidget2 to interactively' \ - ' define the clipping plane for a polydata.' - epilogue = ''' - If no arguments are specified, a vtkSphereSource generates the polydata. - By specifying a .vtp file, the example can operate on arbitrary polydata. -''' - parser = argparse.ArgumentParser(description=description, epilog=epilogue, - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('file_name', nargs='?', default=None, help='A VTK Poly Data file e.g. cow.vtp') - - args = parser.parse_args() - return args.file_name - - if __name__ == '__main__': file_name = get_program_parameters() main(file_name) diff --git a/src/Testing/Baseline/Cxx/Widgets/TestImplicitAnnulusWidget.png b/src/Testing/Baseline/Cxx/Widgets/TestImplicitAnnulusWidget.png new file mode 100644 index 00000000000..92e01a4196f --- /dev/null +++ b/src/Testing/Baseline/Cxx/Widgets/TestImplicitAnnulusWidget.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:241f0fc9174b4780c03951da0b5f6adc685b2a701c77180bd94e094155c66a3d +size 22475 diff --git a/src/Testing/Baseline/PythonicAPI/Widgets/TestImplicitAnnulusWidget.png b/src/Testing/Baseline/PythonicAPI/Widgets/TestImplicitAnnulusWidget.png new file mode 100644 index 00000000000..92e01a4196f --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Widgets/TestImplicitAnnulusWidget.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:241f0fc9174b4780c03951da0b5f6adc685b2a701c77180bd94e094155c66a3d +size 22475 -- GitLab