diff --git a/src/Cxx.md b/src/Cxx.md index 4fd5234af374445477f9789896946bf4e5caf912..3a9d28a6b7ef37bbfa9374a8c370457732ae8e4c 100644 --- a/src/Cxx.md +++ b/src/Cxx.md @@ -783,6 +783,7 @@ This section includes vtkImageData vtkStructuredGrid and vtkRectilinearGrid. [Rainbow](/Cxx/Rendering/Rainbow)| vtkLookupTable | Use and manipulation of vtkLookupTables. [SpecularSpheres](/Cxx/Rendering/SpecularSpheres)| vtkProperty |Demonstrates the effect of specular lighting on spheres. [StippledLine](/Cxx/Rendering/StippledLine)| vtkTexture | Draw a stippled line. +[WalkCow](/Cxx/Rendering/WalkCow) | vtkBYUReader renWin::EraseOff() vtkActor | This generates Figs. 3-31, 3-32, 3-33 found in VTKTextbook.pdf. ## Lighting diff --git a/src/Cxx/Rendering/CMakeLists.txt b/src/Cxx/Rendering/CMakeLists.txt index c9e9d4226635ba33191d6fc7a25a953c6f45cf22..59f5694c81538a50390dfabe1deb8cd5342648ec 100644 --- a/src/Cxx/Rendering/CMakeLists.txt +++ b/src/Cxx/Rendering/CMakeLists.txt @@ -29,6 +29,7 @@ SET(KIT Rendering) SET(NEEDS_ARGS Rainbow Rotations + WalkCow ) SET(DATA ${WikiExamples_SOURCE_DIR}/src/Testing/Data) SET(TEMP ${WikiExamples_BINARY_DIR}/Testing/Temporary) @@ -39,6 +40,9 @@ ADD_TEST(${KIT}-Rotations ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests ADD_TEST(${KIT}-Rainbow ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests TestRainbow ${DATA}/combxyz.bin ${DATA}/combq.bin) +ADD_TEST(${KIT}-WalkCow ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests + TestWalkCow ${DATA}/cow.g) + INCLUDE(${WikiExamples_SOURCE_DIR}/CMake/ExamplesTesting.cmake) endif() diff --git a/src/Cxx/Rendering/WalkCow.cxx b/src/Cxx/Rendering/WalkCow.cxx new file mode 100644 index 0000000000000000000000000000000000000000..09e35a43e7300e6a8f8f84b1dab42ef31f10b4d7 --- /dev/null +++ b/src/Cxx/Rendering/WalkCow.cxx @@ -0,0 +1,480 @@ +// Translated from walkCow.tcl + +#include <vtkActor.h> +#include <vtkAxes.h> +#include <vtkBYUReader.h> +#include <vtkCallbackCommand.h> +#include <vtkCamera.h> +#include <vtkNamedColors.h> +#include <vtkPNGWriter.h> +#include <vtkPolyDataMapper.h> +#include <vtkProperty.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkTransform.h> +#include <vtkWindowToImageFilter.h> + +#include <algorithm> +#include <vector> + +namespace +{ +/* +These Rotate* and Walk functions create a scene where multiple + views of the object exist. + + They all operate in a similar manner, namely: + 1) Accept vtkActor, vtkRenderer, vtkRenderWindow as parameters. + 2) Position the object. + 3) Position the observer with the focal point sent to the centre + of the object. + 4) Render and set EraseOff() in the render window. + Note that: + EraseOff() has to be called after a Render() call + to work in the desired way. + 5) Then rotate or walk the object around the scene. + 6) Write out the scene using Screenshot(). + 6) Set EraseOff() in the render window. + 7) Reset the object position. + +*/ +void Rotate_X(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Rotate_Y(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Rotate_Z(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Rotate_XY(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Rotate_V_0(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Rotate_V_V(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); +void Walk(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin); + +/* +// Used to estimate positions similar to the book illustrations. +static void CameraModifiedCallback(vtkObject* caller, + long unsigned int vtkNotUsed(eventId), + void* vtkNotUsed(clientData), + void* vtkNotUsed(callData)); +*/ + +// Save a screenshot. +void Screenshot(std::string fileName, vtkRenderWindow* renWin); +} + +int main(int argc, char* argv[]) +{ + auto Scale = [](std::vector<double>& v, double scale) { + std::transform(std::begin(v), std::end(v), std::begin(v), + [=](double const& n) { return n / scale; }); + return; + }; + + if (argc != 2) + { + std::cout << "usage: ./WalkCow filename" << std::endl; + std::cout << "where: filename is the file cow.g" << std::endl; + return EXIT_FAILURE; + } + + std::string fileName = argv[1]; + vtkSmartPointer<vtkNamedColors> colors = + vtkSmartPointer<vtkNamedColors>::New(); + // Set the background color. Match those in VTKTextbook.pdf. + auto scale = 256.0; + std::vector<double> bkg1 = {60, 93, 144}; + std::vector<double> bkg2 = {25, 51, 102}; + Scale(bkg1, scale); + colors->SetColor("BkgColor1", bkg1[0], bkg1[1], bkg1[2]); + Scale(bkg2, scale); + colors->SetColor("BkgColor2", bkg2[0], bkg2[1], bkg2[2]); + + vtkSmartPointer<vtkRenderer> ren = vtkSmartPointer<vtkRenderer>::New(); + vtkSmartPointer<vtkRenderWindow> renWin = + vtkSmartPointer<vtkRenderWindow>::New(); + renWin->AddRenderer(ren); + + vtkSmartPointer<vtkRenderWindowInteractor> iren = + vtkSmartPointer<vtkRenderWindowInteractor>::New(); + iren->SetRenderWindow(renWin); + + // The cow pipeline. + vtkSmartPointer<vtkBYUReader> cow = vtkSmartPointer<vtkBYUReader>::New(); + cow->SetGeometryFileName(fileName.c_str()); + cow->Update(); + + vtkSmartPointer<vtkPolyDataMapper> cowMapper = + vtkSmartPointer<vtkPolyDataMapper>::New(); + cowMapper->SetInputConnection(cow->GetOutputPort()); + cowMapper->ScalarVisibilityOff(); + + vtkSmartPointer<vtkActor> cowActor = vtkSmartPointer<vtkActor>::New(); + cowActor->SetMapper(cowMapper); + cowActor->GetProperty()->SetColor(colors->GetColor3d("Wheat").GetData()); + + ren->AddActor(cowActor); + + // Axes pipeline. + vtkSmartPointer<vtkAxes> cowAxesSource = vtkSmartPointer<vtkAxes>::New(); + cowAxesSource->SetScaleFactor(10.0); + cowAxesSource->SetOrigin(0, 0, 0); + + vtkSmartPointer<vtkPolyDataMapper> cowAxesMapper = + vtkSmartPointer<vtkPolyDataMapper>::New(); + cowAxesMapper->SetInputConnection(cowAxesSource->GetOutputPort()); + + vtkSmartPointer<vtkActor> cowAxes = vtkSmartPointer<vtkActor>::New(); + cowAxes->SetMapper(cowAxesMapper); + cowAxes->VisibilityOff(); + + ren->AddActor(cowAxes); + + ren->SetBackground(colors->GetColor3d("BkgColor1").GetData()); + renWin->SetSize(600, 480); + + iren->Initialize(); + cowAxes->VisibilityOn(); + renWin->Render(); + + // Activate this if you want to see the Position and Focal point. + // vtkSmartPointer<vtkCallbackCommand> modifiedCallback = + // vtkSmartPointer<vtkCallbackCommand>::New(); + // modifiedCallback->SetCallback(CameraModifiedCallback); + // ren->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, + // modifiedCallback); + + // These four rotations use the same camera position. + Rotate_X(cowActor, ren, renWin); + Rotate_Y(cowActor, ren, renWin); + Rotate_Z(cowActor, ren, renWin); + Rotate_XY(cowActor, ren, renWin); + + ren->SetBackground(colors->GetColor3d("BkgColor2").GetData()); + Rotate_V_0(cowActor, ren, renWin); + Rotate_V_V(cowActor, ren, renWin); + // Walk() needs to go after Rotate_V_0() or Rotate_V_V(). + Walk(cowActor, ren, renWin); + + // Interact with data. + // Keep the last rendered image. + renWin->EraseOff(); + iren->Start(); + return EXIT_SUCCESS; +} + +namespace +{ + +void Rotate_X(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // Six rotations about the x axis. + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(2, 25, 0); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->GetActiveCamera()->SetViewUp(0, 0, -1); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateX(60); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-31a.png", renWin); + renWin->EraseOn(); +} + +void Rotate_Y(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // Six rotations about the y axis. + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(2, 0, 25); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->GetActiveCamera()->SetViewUp(0, 1, 0); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateY(60); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-31b.png", renWin); + renWin->EraseOn(); +} + +void Rotate_Z(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // Six rotations about the z axis. + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(2, 0, 25); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->GetActiveCamera()->SetViewUp(0, 1, 0); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateZ(60); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-31c.png", renWin); + renWin->EraseOn(); +} + +void Rotate_XY(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // First a rotation about the x axis, then six rotations about the y axis. + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(2, 0, 25); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->GetActiveCamera()->SetViewUp(0, 1, 0); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + cowActor->RotateX(60); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateY(60); + renWin->Render(); + renWin->Render(); + } + cowActor->RotateX(-60); + Screenshot("Fig3-31d.png", renWin); + renWin->EraseOn(); +} + +void Rotate_V_0(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // The cow rotating about a vector passing through her nose. + // With the origin at (0, 0, 0). + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + vtkSmartPointer<vtkTransform> cowPos = vtkSmartPointer<vtkTransform>::New(); + cowPos->Identity(); + cowPos->SetMatrix(cowActor->GetMatrix()); + vtkSmartPointer<vtkTransform> cowTransform = + vtkSmartPointer<vtkTransform>::New(); + cowTransform->Identity(); + cowActor->SetUserMatrix(cowTransform->GetMatrix()); + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(16, 9, -12); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateWXYZ(60, 2.19574, -1.42455, -0.0331036); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-33a.png", renWin); + renWin->EraseOn(); + // Put the cow back on the origin. + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateWXYZ(-60, 2.19574, -1.42455, -0.0331036); + } + cowActor->SetUserMatrix(cowPos->GetMatrix()); + ren->GetActiveCamera()->SetPosition(0, 0, 1); + ren->GetActiveCamera()->SetViewUp(0, 1, 0); + ren->ResetCamera(); +} + +void Rotate_V_V(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // The cow rotating about a vector passing through her nose. + // With the origin at (6.11414, 1.27386, 0.015175). + ren->ResetCamera(); + ren->ResetCameraClippingRange(); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0); + cowActor->SetPosition(0, 0, 0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + vtkSmartPointer<vtkTransform> cowPos = vtkSmartPointer<vtkTransform>::New(); + cowPos->Identity(); + cowPos->SetMatrix(cowActor->GetMatrix()); + cowActor->SetOrigin(6.11414, 1.27386, 0.015175); // The cow's nose + vtkSmartPointer<vtkTransform> cowTransform = + vtkSmartPointer<vtkTransform>::New(); + cowTransform->Identity(); + cowActor->SetUserMatrix(cowTransform->GetMatrix()); + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(31, 23, -21); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateWXYZ(60, 2.19574, -1.42455, -0.0331036); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-33b.png", renWin); + renWin->EraseOn(); + // Put the cow back on the origin. + for (int idx = 0; idx < 6; idx++) + { + cowActor->RotateWXYZ(-60, 2.19574, -1.42455, -0.0331036); + } + cowActor->SetUserMatrix(cowPos->GetMatrix()); +} + +void Walk(vtkActor* cowActor, vtkRenderer* ren, vtkRenderWindow* renWin) +{ + // The cow "walking" around the global origin + vtkSmartPointer<vtkTransform> cowPos = vtkSmartPointer<vtkTransform>::New(); + cowPos->Identity(); + cowPos->SetMatrix(cowActor->GetMatrix()); + cowActor->SetOrientation(0.0, 0.0, 0.0); + cowActor->SetOrigin(0.0, 0.0, 0.0); + // Get the focal point. + double* bounds = cowActor->GetBounds(); + double fp[3]; + for (int i = 0; i < 3; ++i) + { + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0; + } + vtkSmartPointer<vtkTransform> cowTransform = + vtkSmartPointer<vtkTransform>::New(); + cowTransform->Identity(); + cowTransform->Translate(0, 0, 5); + cowActor->SetUserMatrix(cowTransform->GetMatrix()); + // This closely matches the original illustration. + ren->GetActiveCamera()->SetPosition(1, 24, 16); + ren->GetActiveCamera()->SetFocalPoint(fp); + ren->GetActiveCamera()->SetViewUp(0, 0, -1); + ren->ResetCameraClippingRange(); + renWin->Render(); + renWin->Render(); + renWin->EraseOff(); + for (int idx = 0; idx < 6; idx++) + { + cowTransform->Identity(); + cowTransform->RotateY(idx * 60); + cowTransform->Translate(0, 0, 5); + cowActor->SetUserMatrix(cowTransform->GetMatrix()); + renWin->Render(); + renWin->Render(); + } + Screenshot("Fig3-32.png", renWin); + renWin->EraseOn(); + // Walkies are over, put the cow back on the origin. + // cowActor->SetUserMatrix(cowPos->GetMatrix()); +} + +/* +static void CameraModifiedCallback(vtkObject* caller, + long unsigned int vtkNotUsed(eventId), + void* vtkNotUsed(clientData), + void* vtkNotUsed(callData)) +{ + std::cout << caller->GetClassName() << " modified" << std::endl; + vtkCamera* camera = static_cast<vtkCamera*>(caller); + // Print the interesting stuff. + std::cout << "\tPosition: " << camera->GetPosition()[0] << ", " + << camera->GetPosition()[1] << ", " << camera->GetPosition()[2] + << std::endl; + std::cout << "\tFocal point: " << camera->GetFocalPoint()[0] << ", " + << camera->GetFocalPoint()[1] << ", " << camera->GetFocalPoint()[2] + << std::endl; +} +*/ + +void Screenshot(std::string fileName, vtkRenderWindow* renWin) +{ + vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = + vtkSmartPointer<vtkWindowToImageFilter>::New(); + windowToImageFilter->SetInput(renWin); +#if VTK_MAJOR_VERSION > 8 || VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 1 + windowToImageFilter->SetScale(1); // image quality +#else + windowToImageFilter->SetMagnification(1); // image quality +#endif + // We are not recording the alpha (transparency) channel. + // windowToImageFilter->SetInputBufferTypeToRGBA(); + windowToImageFilter->SetInputBufferTypeToRGB(); + // Read from the front buffer. + windowToImageFilter->ReadFrontBufferOff(); + windowToImageFilter->Update(); + + vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New(); + writer->SetFileName(fileName.c_str()); + writer->SetInputConnection(windowToImageFilter->GetOutputPort()); + writer->Write(); +} + +} diff --git a/src/Cxx/Rendering/WalkCow.md b/src/Cxx/Rendering/WalkCow.md new file mode 100644 index 0000000000000000000000000000000000000000..3221ab11c88b9e2bc0edfe3d1bbf5378a4294b72 --- /dev/null +++ b/src/Cxx/Rendering/WalkCow.md @@ -0,0 +1,2 @@ +### Description +This generates Fig 3-31: Rotations of a cow about her axes.; Fig. 3-32: The cow "walking" around the global origin; Fig. 3-33: The cow rotating about a vector passing through her nose found in VTKTextbook.pdf. diff --git a/src/Python.md b/src/Python.md index a917604269f3831550771d19ba632d93e47ad2a3..732544f083cbbade4f65becd413bf910b59ffb9d 100644 --- a/src/Python.md +++ b/src/Python.md @@ -161,6 +161,11 @@ This section includes examples of manipulating meshes. [Variant](/Python/Variant) | vtkVariant | vtkVersion | +## Rendering +| Example Name | Classes Demonstrated | Description | Image | +|--------------|----------------------|-------------|-------| +[WalkCow](/Python/Rendering/WalkCow) | vtkBYUReader renWin::EraseOff() vtkActor | This generates Figs. 3-31, 3-32, 3-33 found in VTKTextbook.pdf. + ## Visualization | Example Name | Classes Demonstrated | Description | Image | diff --git a/src/Python/Rendering/WalkCow.md b/src/Python/Rendering/WalkCow.md new file mode 100644 index 0000000000000000000000000000000000000000..3221ab11c88b9e2bc0edfe3d1bbf5378a4294b72 --- /dev/null +++ b/src/Python/Rendering/WalkCow.md @@ -0,0 +1,2 @@ +### Description +This generates Fig 3-31: Rotations of a cow about her axes.; Fig. 3-32: The cow "walking" around the global origin; Fig. 3-33: The cow rotating about a vector passing through her nose found in VTKTextbook.pdf. diff --git a/src/Python/Rendering/WalkCow.py b/src/Python/Rendering/WalkCow.py new file mode 100644 index 0000000000000000000000000000000000000000..f6b2cb6d4447cc68bcb343097be0a996209a5189 --- /dev/null +++ b/src/Python/Rendering/WalkCow.py @@ -0,0 +1,393 @@ +#!/usr/local/bin/python + +# Translated from walkCow.tcl + +import vtk + + +def main(): + file_name = get_program_parameters() + + colors = vtk.vtkNamedColors() + # Set the background color. Match those in VTKTextbook.pdf. + bkg1 = map(lambda x: x / 256.0, [60, 93, 144]) + bkg2 = map(lambda x: x / 256.0, [25, 51, 102]) + colors.SetColor("BkgColor1", *bkg1) + colors.SetColor("BkgColor2", *bkg2) + + ren = vtk.vtkRenderer() + renWin = vtk.vtkRenderWindow() + renWin.AddRenderer(ren) + + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(renWin) + + # The cow pipeline. + cow = vtk.vtkBYUReader() + cow.SetGeometryFileName(file_name) + cow.Update() + + cowMapper = vtk.vtkPolyDataMapper() + cowMapper.SetInputConnection(cow.GetOutputPort()) + cowMapper.ScalarVisibilityOff() + + cowActor = vtk.vtkActor() + cowActor.SetMapper(cowMapper) + cowActor.GetProperty().SetColor(colors.GetColor3d("Wheat")) + + ren.AddActor(cowActor) + + # Axes pipeline. + cowAxesSource = vtk.vtkAxes() + cowAxesSource.SetScaleFactor(10.0) + cowAxesSource.SetOrigin(0, 0, 0) + + cowAxesMapper = vtk.vtkPolyDataMapper() + cowAxesMapper.SetInputConnection(cowAxesSource.GetOutputPort()) + + cowAxes = vtk.vtkActor() + cowAxes.SetMapper(cowAxesMapper) + cowAxes.VisibilityOff() + + ren.AddActor(cowAxes) + + ren.SetBackground(colors.GetColor3d("BkgColor1")) + renWin.SetSize(600, 480) + + iren.Initialize() + cowAxes.VisibilityOn() + renWin.Render() + + # A general comment: + # EraseOff() has to be called after a Render() call to work in the desired way. + + # Activate this if you want to see the Position and Focal point. + # ren.GetActiveCamera().AddObserver('ModifiedEvent', CameraModifiedCallback) + + # These four walks use the same camera position. + Rotate_X(cowActor, ren, renWin) + Rotate_Y(cowActor, ren, renWin) + Rotate_Z(cowActor, ren, renWin) + Rotate_XY(cowActor, ren, renWin) + + ren.SetBackground(colors.GetColor3d("BkgColor2")) + Rotate_V_0(cowActor, ren, renWin) + Rotate_V_V(cowActor, ren, renWin) + # Walk() needs to go after Rotate_V_0() or Rotate_V_V(). + Walk(cowActor, ren, renWin) + + # Interact with data. + renWin.EraseOff() + iren.Start() + + +def get_program_parameters(): + import argparse + description = 'Produce figures: 3-31, 3-32, 3-33 from the VTK Textbook.' + epilogue = ''' + Produce figures 3-31, 3-32, 3-33 from the VTK Textbook. + It is a translation of the original WalkCow.tcl with a few additional enhancements. + ''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue) + parser.add_argument('filename', help='The file cow.g.') + args = parser.parse_args() + return args.filename + + +""" + These Rotate* and Walk functions create a scene where multiple + views of the object exist. + + They all operate in a similar manner, namely: + 1) Accept vtkActor, vtkRenderer, vtkRenderWindow as parameters. + 2) Position the object. + 3) Position the observer with the focal point sent to the centre + of the object. + 4) Render and set EraseOff() in the render window. + Note that: + EraseOff() has to be called after a Render() call + to work in the desired way. + 5) Then rotate or Walk the object around the scene. + 6) Write out the scene using Screenshot(). + 6) Set EraseOff() in the render window. + 7) Reset the object position. + +""" + + +def Rotate_X(cowActor, ren, renWin): + # Six rotations about the x axis. + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + # This closely matches the original illustration. + ren.GetActiveCamera().SetPosition(2, 25, 0) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.GetActiveCamera().SetViewUp(0, 0, -1) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(0, 6): + cowActor.RotateX(60) + renWin.Render() + renWin.Render() + Screenshot("Fig3-31a.png", renWin) + renWin.EraseOn() + + +def Rotate_Y(cowActor, ren, renWin): + # Six rotations about the y axis. + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + # This closely matches the original illustration. + ren.GetActiveCamera().SetPosition(2, 0, 25) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.GetActiveCamera().SetViewUp(0, 1, 0) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(0, 6): + cowActor.RotateY(60) + renWin.Render() + renWin.Render() + Screenshot("Fig3-31b.png", renWin) + renWin.EraseOn() + + +def Rotate_Z(cowActor, ren, renWin): + # Six rotations about the z axis. + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + # This closely matches the original illustration. + # ren.GetActiveCamera().SetPosition(2, 0, 25) + ren.GetActiveCamera().SetPosition(2, 0, 25) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.GetActiveCamera().SetViewUp(0, 1, 0) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(0, 6): + cowActor.RotateZ(60) + renWin.Render() + renWin.Render() + Screenshot("Fig3-31c.png", renWin) + renWin.EraseOn() + + +def Rotate_XY(cowActor, ren, renWin): + # First a rotation about the x axis, then six rotations about the y axis. + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + # This closely matches the original illustration. + # ren.GetActiveCamera().SetPosition(2, 0, 24) + ren.GetActiveCamera().SetPosition(2, 0, 25) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.GetActiveCamera().SetViewUp(0, 1, 0) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + cowActor.RotateX(60) + for idx in range(0, 6): + cowActor.RotateY(60) + renWin.Render() + renWin.Render() + cowActor.RotateX(-60) + Screenshot("Fig3-31d.png", renWin) + renWin.EraseOn() + + +def Rotate_V_0(cowActor, ren, renWin): + # The cow rotating about a vector passing through her nose. + # With the origin at (0, 0, 0). + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + cowPos = vtk.vtkTransform() + cowPos.Identity() + cowPos.SetMatrix(cowActor.GetMatrix()) + cowTransform = vtk.vtkTransform() + cowTransform.Identity() + cowActor.SetUserMatrix(cowTransform.GetMatrix()) + # This closely matches the original illustration. + ren.GetActiveCamera().SetPosition(16, 9, -12) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(0, 6): + cowActor.RotateWXYZ(60, 2.19574, -1.42455, -0.0331036) + renWin.Render() + renWin.Render() + Screenshot("Fig3-33a.png", renWin) + renWin.EraseOn() + # Put the cow back on the origin. + for idx in range(0, 6): + cowActor.RotateWXYZ(-60, 2.19574, -1.42455, -0.0331036) + cowActor.SetUserMatrix(cowPos.GetMatrix()) + ren.GetActiveCamera().SetPosition(0, 0, 1) + ren.GetActiveCamera().SetViewUp(0, 1, 0) + ren.ResetCamera() + + +def Rotate_V_V(cowActor, ren, renWin): + # The cow rotating about a vector passing through her nose. + # With the origin at (6.11414, 1.27386, 0.015175). + ren.ResetCamera() + ren.ResetCameraClippingRange() + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0) + cowActor.SetPosition(0, 0, 0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + cowPos = vtk.vtkTransform() + cowPos.Identity() + cowPos.SetMatrix(cowActor.GetMatrix()) + cowActor.SetOrigin(6.11414, 1.27386, 0.015175) # The cow's nose + cowTransform = vtk.vtkTransform() + cowTransform.Identity() + cowActor.SetUserMatrix(cowTransform.GetMatrix()) + # This closely matches the original illustration. + ren.GetActiveCamera().SetPosition(31, 23, -21) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(0, 6): + cowActor.RotateWXYZ(60, 2.19574, -1.42455, -0.0331036) + renWin.Render() + renWin.Render() + Screenshot("Fig3-33b.png", renWin) + renWin.EraseOn() + # Put the cow back on the origin. + for idx in range(0, 6): + cowActor.RotateWXYZ(-60, 2.19574, -1.42455, -0.0331036) + cowActor.SetUserMatrix(cowPos.GetMatrix()) + + +def Walk(cowActor, ren, renWin): + # The cow "walking" around the global origin + cowPos = vtk.vtkTransform() + cowPos.Identity() + cowPos.SetMatrix(cowActor.GetMatrix()) + cowActor.SetOrientation(0.0, 0.0, 0.0) + cowActor.SetOrigin(0.0, 0.0, 0.0) + # Get the focal point. + bounds = cowActor.GetBounds() + fp = [0.0] * 3 + for i in range(0, 3): + fp[i] = (bounds[i * 2 + 1] + bounds[i * 2]) / 2.0 + cowTransform = vtk.vtkTransform() + cowTransform.Identity() + cowTransform.Translate(0, 0, 5) + cowActor.SetUserMatrix(cowTransform.GetMatrix()) + # This closely matches the original illustration. + ren.GetActiveCamera().SetPosition(1, 24, 16) + ren.GetActiveCamera().SetFocalPoint(fp) + ren.GetActiveCamera().SetViewUp(0, 0, -1) + ren.ResetCameraClippingRange() + renWin.Render() + renWin.Render() + renWin.EraseOff() + for idx in range(1, 7): + cowTransform.Identity() + cowTransform.RotateY(idx * 60) + cowTransform.Translate(0, 0, 5) + cowActor.SetUserMatrix(cowTransform.GetMatrix()) + renWin.Render() + renWin.Render() + Screenshot("Fig3-32.png", renWin) + renWin.EraseOn() + # Walkies are over, put the cow back on the origin. + # cowActor.SetUserMatrix(cowPos.GetMatrix()) + + +def CameraModifiedCallback(caller): + """ + Used to estimate positions similar to the book illustrations. + :param caller: + :return: + """ + print(caller.GetClassName(), "modified") + # Print the interesting stuff. + print("\tPosition: ", + caller.GetPosition()[0], ", ", + caller.GetPosition()[1], ", ", + caller.GetPosition()[2]) + print("\tFocal point: ", + caller.GetFocalPoint()[0], ", ", + caller.GetFocalPoint()[1], ", ", + caller.GetFocalPoint()[2]) + + +def Screenshot(fileName, renWin): + """ + Save a screenshot. + :param fileName: + :param renWin: + :return: + """ + windowToImageFilter = vtk.vtkWindowToImageFilter() + windowToImageFilter.SetInput(renWin) + windowToImageFilter.SetScale(1) # image quality + # We are not recording the alpha (transparency) channel. + # windowToImageFilter.SetInputBufferTypeToRGBA() + windowToImageFilter.SetInputBufferTypeToRGB() + # Read from the front buffer. + windowToImageFilter.ReadFrontBufferOff() + windowToImageFilter.Update() + + writer = vtk.vtkPNGWriter() + writer.SetFileName(fileName) + writer.SetInputConnection(windowToImageFilter.GetOutputPort()) + writer.Write() + + +if __name__ == '__main__': + main()