diff --git a/src/Cxx.md b/src/Cxx.md index 45372abf982c1bcfd3133283559e08b72e8880a7..8318e7ad775f06c8101e5b69edaa1f2bebf0663b 100644 --- a/src/Cxx.md +++ b/src/Cxx.md @@ -870,6 +870,7 @@ This section includes vtkUnstructuredGrid. [Cone4](/Cxx/Rendering/Cone4) | Modifying properties and transformation matrix based on the VTK example Cone4.cxx. [DiffuseSpheres](/Cxx/Rendering/DiffuseSpheres) | Demonstrates the effect of diffuse lighting on spheres. [FlatVersusGouraud](/Cxx/Rendering/FlatVersusGouraud) | Flat and Gouraud shading. Different shading methods can dramatically improve the look of an object represented with polygons. On the top, flat shading uses a constant surface normal across each polygon. On the bottom, Gouraud shading interpolates normals from polygon vertices to give a smoother look. +[GradientBackground](/Cxx/Rendering/GradientBackground) | Demonstrates the background shading options. [HiddenLineRemoval](/Cxx/Rendering/HiddenLineRemoval) | Hidden lines removed. [Mace](/Cxx/Rendering/Mace) | An example of multiple inputs and outputs. [Model](/Cxx/Rendering/Model) | Illustrative diagram of graphics objects. diff --git a/src/Cxx/Rendering/CMakeLists.txt b/src/Cxx/Rendering/CMakeLists.txt index 7a25ff4b1c446265504a1f417f3c6615e6a5f206..d212d9446cf13d297f1b2a4c22f6e5fafdce1f20 100644 --- a/src/Cxx/Rendering/CMakeLists.txt +++ b/src/Cxx/Rendering/CMakeLists.txt @@ -61,6 +61,8 @@ Requires_Cxx_Version(PBR_Mapping ${CXX_VERSION_MIN} ALL_FILES) Requires_Cxx_Version(PBR_Materials ${CXX_VERSION_MIN} ALL_FILES) Requires_Cxx_Version(PBR_Materials_Coat ${CXX_VERSION_MIN} ALL_FILES) +Requires_Cxx_Version(GradientBackground ${CXX_VERSION_MIN} ALL_FILES) + include(${WikiExamples_SOURCE_DIR}/CMake/RequiresModule.cmake) Requires_Module(PBR_Skybox cli11) Requires_Module(PBR_Skybox_Texturing cli11) @@ -86,6 +88,8 @@ Requires_Module(PBR_Mapping jsoncpp) Requires_Module(PBR_Materials jsoncpp) Requires_Module(PBR_Materials_Coat jsoncpp) +Requires_Module(GradientBackground cli11) + foreach(SOURCE_FILE ${ALL_FILES}) string(REPLACE ".cxx" "" TMP ${SOURCE_FILE}) @@ -103,6 +107,7 @@ if (BUILD_TESTING) set(KIT Rendering) set(NEEDS_ARGS FlatVersusGouraud + GradientBackground HiddenLineRemoval InterpolateCamera MotionBlur @@ -135,6 +140,9 @@ if (BUILD_TESTING) add_test(${KIT}-FlatVersusGouraud ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests TestFlatVersusGouraud ${DATA}/cow.obj) + add_test(${KIT}-GradientBackground ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests + TestGradientBackground ${DATA}/star-wars-vader-tie-fighter.obj) + add_test(${KIT}-HiddenLineRemoval ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests TestHiddenLineRemoval ${DATA}/cow.obj) diff --git a/src/Cxx/Rendering/GradientBackground.cxx b/src/Cxx/Rendering/GradientBackground.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f4a959ecd431742e34a399ca155e151fb65974cb --- /dev/null +++ b/src/Cxx/Rendering/GradientBackground.cxx @@ -0,0 +1,383 @@ +// Based on: +// https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/Core/Testing/Cxx/TestGradientBackground.cxx?ref_type=heads +// See: +// [New in VTK 9.3: Radial Gradient +// Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/) + +#include <vtkActor.h> +#include <vtkActor2D.h> +#include <vtkColor.h> +#include <vtkConeSource.h> +#include <vtkInteractorStyleTrackballCamera.h> +#include <vtkNamedColors.h> +#include <vtkNew.h> +#include <vtkPolyDataMapper.h> +#include <vtkProperty.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkRenderer.h> +#include <vtkSphereSource.h> +#include <vtkTextMapper.h> +#include <vtkTextProperty.h> +#include <vtkViewport.h> +#include <vtk_cli11.h> + +// Readers +#include <vtkBYUReader.h> +#include <vtkOBJReader.h> +#include <vtkPLYReader.h> +#include <vtkPolyDataReader.h> +#include <vtkSTLReader.h> +#include <vtkXMLPolyDataReader.h> + +#include <vtkPolyDataMapper2D.h> +#include <vtkPolyLine.h> +#include <vtkProperty2D.h> + +#include <algorithm> +#include <array> +#include <cstdlib> +#include <filesystem> +#include <iomanip> +#include <iostream> +#include <string> + +namespace fs = std::filesystem; + +namespace { + +/** + * @brief ReadPolyData Read from a file containing vtkPolyData. + * + * ReadPolyData + * If the path is empty a cone is returned. + * If the extension is unknown a sphere is returned. + * + * @param path - The std::filesystem path to the file. + * @return The vtkPolyData. + */ +vtkNew<vtkPolyData> ReadPolyData(fs::path const& path); + +/** + * @brief ViewportBorder Set a border around a viewport. + * + * @param renderer - The renderer corresponding to the viewport. + * @param sides - A boolean array corresponding to [top, left, bottom, right]. + * @param borderColor - The color of the border. + * @param borderWidth - The width of the border. + */ +void ViewportBorder(vtkRenderer* renderer, const std::array<bool, 4>& sides, + std::string const& borderColor, + double const& borderWidth = 2); + +} // namespace + +int main(int argc, char* argv[]) +{ + + CLI::App app{"Demonstrates the background shading options."}; + + // Define options + std::string fileName{""}; + app.add_option("fileName", fileName, + "A optional path to a file that contains vtkPolyData e.g. " + "star-wars-vader-tie-fighter.obj"); + CLI11_PARSE(app, argc, argv); + + auto path = fs::path(fileName); + if (!path.empty()) + { + if (!fs::is_regular_file(path)) + { + std::cerr << "Unable to find: " << path << std::endl; + return EXIT_FAILURE; + } + } + + auto pd = ReadPolyData(path); + + vtkNew<vtkRenderWindow> renWin; + renWin->SetWindowName("GradientBackground"); + + vtkNew<vtkRenderWindowInteractor> iRen; + vtkNew<vtkRenderer> renderers[4]; + + // For each gradient specify the mode. + vtkViewport::GradientModes modes[4] = { + vtkViewport::GradientModes::VTK_GRADIENT_VERTICAL, + vtkViewport::GradientModes::VTK_GRADIENT_HORIZONTAL, + vtkViewport::GradientModes::VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_SIDE, + vtkViewport::GradientModes::VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_CORNER, + }; + + vtkNew<vtkNamedColors> colors; + + vtkNew<vtkPolyDataMapper> mapper; + mapper->SetInputData(pd); + + vtkNew<vtkActor> actor; + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(colors->GetColor3d("Honeydew").GetData()); + actor->GetProperty()->SetSpecular(0.3); + actor->GetProperty()->SetSpecularPower(60.0); + + const auto renWidth = 640; + const auto renHeight = 480; + + // The bounds for each view port. + double xmins[4] = {0.0, 0.5, 0.0, 0.5}; + double ymins[4] = {0.0, 0.0, 0.5, 0.5}; + double xmaxs[4] = {0.5, 1.0, 0.5, 1.0}; + double ymaxs[4] = {0.5, 0.5, 1.0, 1.0}; + + // Here we select and name the colors. + // Feel free to change colors. + const auto bottomColor = colors->GetColor3d("Gold"); + const auto topColor = colors->GetColor3d("OrangeRed"); + const auto leftColor = colors->GetColor3d("Gold"); + const auto rightColor = colors->GetColor3d("OrangeRed"); + const auto centerColor = colors->GetColor3d("Gold"); + const auto sideColor = colors->GetColor3d("OrangeRed"); + const auto cornerColor = colors->GetColor3d("OrangeRed"); + + const std::array<std::string, 4> viewportTitle{"Vertical", "Horizontal", + "Radial Farthest Side", + "Radial Farthest Corner"}; + + // Create one text property for all. + vtkNew<vtkTextProperty> textProperty; + textProperty->SetJustificationToCentered(); + textProperty->SetFontSize(renHeight / 12); + textProperty->SetColor(colors->GetColor3d("MidnightBlue").GetData()); + + vtkNew<vtkTextMapper> textMappers[4]; + vtkNew<vtkActor2D> textActors[4]; + + // Define borders for the viewports {top, left, bottom, right}. + std::array<bool, 4> lb{false, true, true, false}; + std::array<bool, 4> lbr{false, true, true, true}; + std::array<bool, 4> tlb{true, true, true, false}; + std::array<bool, 4> tlbr{true, true, true, true}; + std::string borderColor = "DarkGreen"; + auto borderWidth = 4.0; + + for (int i = 0; i < 4; ++i) + { + auto textMapper = textMappers[i].Get(); + textMapper->SetInput(viewportTitle[i].c_str()); + textMapper->SetTextProperty(textProperty); + + auto textActor = textActors[i].Get(); + textActor->SetMapper(textMapper); + textActor->SetPosition(renWidth / 2, 8); + + auto ren = renderers[i].Get(); + ren->AddActor(textActor); + ren->AddActor(actor); + ren->GradientBackgroundOn(); + ren->SetGradientMode(modes[i]); + + ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]); + + switch (i) + { + case 0: + default: + // Vertical + ren->SetBackground(bottomColor.GetData()); + ren->SetBackground2(topColor.GetData()); + ViewportBorder(ren, lb, borderColor, borderWidth); + break; + case 1: + // Horizontal + ren->SetBackground(leftColor.GetData()); + ren->SetBackground2(rightColor.GetData()); + ViewportBorder(ren, lbr, borderColor, borderWidth); + break; + case 2: + // Radial Farthest Side + ren->SetBackground(centerColor.GetData()); + ren->SetBackground2(sideColor.GetData()); + ViewportBorder(ren, tlb, borderColor, borderWidth); + break; + case 3: + // Radial Farthest Corner + ren->SetBackground(centerColor.GetData()); + ren->SetBackground2(cornerColor.GetData()); + ViewportBorder(ren, tlbr, borderColor, borderWidth); + break; + } + + renWin->AddRenderer(ren); + } + + renWin->SetInteractor(iRen); + renWin->Render(); + + vtkNew<vtkInteractorStyleTrackballCamera> style; + iRen->SetInteractorStyle(style); + + iRen->Initialize(); + iRen->UpdateSize(renWidth * 2, renHeight * 2); + + iRen->Start(); + + return EXIT_SUCCESS; +} + +namespace { + +vtkNew<vtkPolyData> ReadPolyData(fs::path const& path) +{ + + vtkNew<vtkPolyData> polyData; + + if (path.empty()) + { + // Default to a cone if the path is empty. + vtkNew<vtkConeSource> source; + source->SetResolution(25); + source->SetDirection(0, 1, 0); + source->SetHeight(1); + source->Update(); + polyData->DeepCopy(source->GetOutput()); + return polyData; + } + + std::string extension = path.extension().generic_string(); + std::transform(extension.begin(), extension.end(), extension.begin(), + [](char c) { return std::tolower(c); }); + + if (extension == ".ply") + { + vtkNew<vtkPLYReader> reader; + reader->SetFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else if (extension == ".vtp") + { + vtkNew<vtkXMLPolyDataReader> reader; + reader->SetFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else if (extension == ".obj") + { + vtkNew<vtkOBJReader> reader; + reader->SetFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else if (extension == ".stl") + { + vtkNew<vtkSTLReader> reader; + reader->SetFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else if (extension == ".vtk") + { + vtkNew<vtkPolyDataReader> reader; + reader->SetFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else if (extension == ".g") + { + vtkNew<vtkBYUReader> reader; + reader->SetGeometryFileName(path.c_str()); + reader->Update(); + polyData->DeepCopy(reader->GetOutput()); + } + else + { + std::cerr << "Warning: " << path + << " unknown extension, using a sphere instead." << std::endl; + vtkNew<vtkSphereSource> source; + source->SetPhiResolution(50); + source->SetThetaResolution(50); + source->Update(); + polyData->DeepCopy(source->GetOutput()); + } + return polyData; +} + +void ViewportBorder(vtkRenderer* renderer, std::array<bool, 4> const& sides, + std::string const& borderColor, double const& borderWidth) +{ + vtkNew<vtkNamedColors> colors; + + // Points start at upper right and proceed anti-clockwise. + vtkNew<vtkPoints> points; + points->SetNumberOfPoints(4); + points->InsertPoint(0, 1, 1, 0); + points->InsertPoint(1, 0, 1, 0); + points->InsertPoint(2, 0, 0, 0); + points->InsertPoint(3, 1, 0, 0); + + vtkNew<vtkCellArray> cells; + cells->Initialize(); + + if (sides[0]) + { + // Top + vtkNew<vtkPolyLine> top; + top->GetPointIds()->SetNumberOfIds(2); + top->GetPointIds()->SetId(0, 0); + top->GetPointIds()->SetId(1, 1); + cells->InsertNextCell(top); + } + if (sides[1]) + { + // Left + vtkNew<vtkPolyLine> left; + left->GetPointIds()->SetNumberOfIds(2); + left->GetPointIds()->SetId(0, 1); + left->GetPointIds()->SetId(1, 2); + cells->InsertNextCell(left); + } + if (sides[2]) + { + // Bottom + vtkNew<vtkPolyLine> bottom; + bottom->GetPointIds()->SetNumberOfIds(2); + bottom->GetPointIds()->SetId(0, 2); + bottom->GetPointIds()->SetId(1, 3); + cells->InsertNextCell(bottom); + } + if (sides[3]) + { + // Right + vtkNew<vtkPolyLine> right; + right->GetPointIds()->SetNumberOfIds(2); + right->GetPointIds()->SetId(0, 3); + right->GetPointIds()->SetId(1, 0); + cells->InsertNextCell(right); + } + + // Now make the polydata and display it. + vtkNew<vtkPolyData> poly; + poly->Initialize(); + poly->SetPoints(points); + poly->SetLines(cells); + + // Use normalized viewport coordinates since + // they are independent of window size. + vtkNew<vtkCoordinate> coordinate; + coordinate->SetCoordinateSystemToNormalizedViewport(); + + vtkNew<vtkPolyDataMapper2D> mapper; + mapper->SetInputData(poly); + mapper->SetTransformCoordinate(coordinate); + + vtkNew<vtkActor2D> actor; + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(colors->GetColor3d(borderColor).GetData()); + + // Line width should be at least 2 to be visible at extremes. + actor->GetProperty()->SetLineWidth(borderWidth); + renderer->AddViewProp(actor); +} + +} // namespace diff --git a/src/Cxx/Rendering/GradientBackground.md b/src/Cxx/Rendering/GradientBackground.md new file mode 100644 index 0000000000000000000000000000000000000000..d148d224a57f6955d08ee70576012b8c530e9126 --- /dev/null +++ b/src/Cxx/Rendering/GradientBackground.md @@ -0,0 +1,22 @@ +### Description + +Demonstrates the gradient backgrounds available in VTK. + +The gradient background modes are: + +- Vertical +- Horizontal +- Radial Farthest Side +- Radial Farthest Corner + +The user can also edit the code to change the stop colors marking the beginning and end points in a gradient. + +An option is provided for the user to read in a data file so that more interesting objects can be viewed. + +The viewport border can also be set and colored. + +For more information, see [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/) + +!!! note VTK 9.3 or later is required. + +!!! note The C++ version requires C++ 17 or later as std::filesystem is used. diff --git a/src/Python.md b/src/Python.md index 6fcae4fa2c3163019b5da604d5ee6ab602a42809..580fcc396bf87b94ec8141d283c97cdf2a425794 100644 --- a/src/Python.md +++ b/src/Python.md @@ -449,6 +449,7 @@ This section includes vtkUnstructuredGrid. [Cone4](/Python/Rendering/Cone4) | Modifying properties and transformation matrix based on the VTK example Cone4.py. [DiffuseSpheres](/Python/Rendering/DiffuseSpheres) | Demonstrates the effect of diffuse lighting on spheres. [FlatVersusGouraud](/Python/Rendering/FlatVersusGouraud) | Flat and Gouraud shading. Different shading methods can dramatically improve the look of an object represented with polygons. On the top, flat shading uses a constant surface normal across each polygon. On the bottom, Gouraud shading interpolates normals from polygon vertices to give a smoother look. +[GradientBackground](/Python/Rendering/GradientBackground) | Demonstrates the background shading options. [Mace](/Python/Rendering/Mace) | An example of multiple inputs and outputs. [Model](/Python/Rendering/Model) | Illustrative diagram of graphics objects. [MotionBlur](/Python/Rendering/MotionBlur) | Example of motion blur. diff --git a/src/Python/Rendering/GradientBackground.md b/src/Python/Rendering/GradientBackground.md new file mode 100644 index 0000000000000000000000000000000000000000..d148d224a57f6955d08ee70576012b8c530e9126 --- /dev/null +++ b/src/Python/Rendering/GradientBackground.md @@ -0,0 +1,22 @@ +### Description + +Demonstrates the gradient backgrounds available in VTK. + +The gradient background modes are: + +- Vertical +- Horizontal +- Radial Farthest Side +- Radial Farthest Corner + +The user can also edit the code to change the stop colors marking the beginning and end points in a gradient. + +An option is provided for the user to read in a data file so that more interesting objects can be viewed. + +The viewport border can also be set and colored. + +For more information, see [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/) + +!!! note VTK 9.3 or later is required. + +!!! note The C++ version requires C++ 17 or later as std::filesystem is used. diff --git a/src/Python/Rendering/GradientBackground.py b/src/Python/Rendering/GradientBackground.py new file mode 100755 index 0000000000000000000000000000000000000000..3764c94e463c68589d5d8426616e6a7e0d5e3877 --- /dev/null +++ b/src/Python/Rendering/GradientBackground.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python + +# Based on: +# https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/Core/Testing/Cxx/TestGradientBackground.cxx?ref_type=heads +# See: +# [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/) + +from pathlib import Path + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingFreeType +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonCore import vtkPoints +from vtkmodules.vtkCommonDataModel import ( + vtkCellArray, + vtkPolyData, + vtkPolyLine +) +from vtkmodules.vtkFiltersSources import ( + vtkConeSource, + vtkSphereSource +) +from vtkmodules.vtkIOGeometry import ( + vtkBYUReader, + vtkOBJReader, + vtkSTLReader +) +from vtkmodules.vtkIOLegacy import vtkPolyDataReader +from vtkmodules.vtkIOPLY import vtkPLYReader +from vtkmodules.vtkIOXML import vtkXMLPolyDataReader +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkActor2D, + vtkCoordinate, + vtkPolyDataMapper, + vtkPolyDataMapper2D, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer, + vtkTextMapper, + vtkTextProperty, + vtkViewport +) + + +def get_program_parameters(argv): + import argparse + description = 'Demonstrates the background shading options.' + epilogue = ''' + ''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-f', '--file_name', default=None, + help='An optional file name, e.g. star-wars-vader-tie-fighter.obj.') + args = parser.parse_args() + return args.file_name + + +def main(fn): + if fn: + fp = Path(fn) + if not fp.is_file(): + print(f'The path: {fp} does not exist.') + return + else: + fp = None + + pd = read_polydata_(fp) + + ren_win = vtkRenderWindow() + ren_win.SetWindowName('GradientBackground') + + iren = vtkRenderWindowInteractor() + renderers = [] + + # For each gradient specify the mode. + modes = [ + vtkViewport.GradientModes.VTK_GRADIENT_VERTICAL, + vtkViewport.GradientModes.VTK_GRADIENT_HORIZONTAL, + vtkViewport.GradientModes.VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_SIDE, + vtkViewport.GradientModes.VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_CORNER, + ] + + colors = vtkNamedColors() + + mapper = vtkPolyDataMapper() + mapper.SetInputData(pd) + + actor = vtkActor() + actor.SetMapper(mapper) + actor.GetProperty().SetColor(colors.GetColor3d('Honeydew')) + actor.GetProperty().SetSpecular(0.3) + actor.GetProperty().SetSpecularPower(60.0) + + ren_width = 640 + ren_height = 480 + + # The bounds for each view port. + xmins = [0.0, 0.5, 0.0, 0.5] + ymins = [0.0, 0.0, 0.5, 0.5] + xmaxs = [0.5, 1.0, 0.5, 1.0] + ymaxs = [0.5, 0.5, 1.0, 1.0] + + # Here we select and name the colors. + # Feel free to change colors. + bottom_color = colors.GetColor3d('Gold') + top_color = colors.GetColor3d('OrangeRed') + left_color = colors.GetColor3d('Gold') + right_color = colors.GetColor3d('OrangeRed') + center_color = colors.GetColor3d('Gold') + side_color = colors.GetColor3d('OrangeRed') + corner_color = colors.GetColor3d('OrangeRed') + + viewport_title = ["Vertical", + "Horizontal", + "Radial Farthest Side", + "Radial Farthest Corner", + ] + + # Create one text property for all. + text_property = vtkTextProperty() + text_property.SetJustificationToCentered() + text_property.SetFontSize(ren_height // 12) + text_property.SetColor(colors.GetColor3d('MidnightBlue')) + + text_mappers = [] + text_actors = [] + + # Define borders for the viewports = [top, left, bottom, right]. + lb = [False, True, True, False] + lbr = [False, True, True, True] + tlb = [True, True, True, False] + tlbr = [True, True, True, True] + border_color = 'DarkGreen' + border_width = 4.0 + + for i in range(0, 4): + text_mappers.append(vtkTextMapper()) + text_mappers[i].SetInput(viewport_title[i]) + text_mappers[i].SetTextProperty(text_property) + + text_actors.append(vtkActor2D()) + text_actors[i].SetMapper(text_mappers[i]) + text_actors[i].SetPosition(ren_width / 2, 8) + + renderers.append(vtkRenderer()) + renderers[i].AddActor(text_actors[i]) + renderers[i].AddActor(actor) + renderers[i].GradientBackgroundOn() + renderers[i].SetGradientMode(modes[i]) + + renderers[i].SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]) + + if i == 1: + # Horizontal + renderers[i].SetBackground(left_color) + renderers[i].SetBackground2(right_color) + viewport_border(renderers[i], lbr, border_color, border_width) + elif i == 2: + # Radial Farthest Side + renderers[i].SetBackground(center_color) + renderers[i].SetBackground2(side_color) + viewport_border(renderers[i], tlb, border_color, border_width) + elif i == 3: + # Radial Farthest Corner + renderers[i].SetBackground(center_color) + renderers[i].SetBackground2(corner_color) + viewport_border(renderers[i], tlbr, border_color, border_width) + else: + # Vertical + renderers[i].SetBackground(bottom_color) + renderers[i].SetBackground2(top_color) + viewport_border(renderers[i], lb, border_color, border_width) + + ren_win.AddRenderer(renderers[i]) + + ren_win.SetInteractor(iren) + ren_win.Render() + + style = vtkInteractorStyleTrackballCamera() + iren.SetInteractorStyle(style) + + iren.Initialize() + iren.UpdateSize(ren_width * 2, ren_height * 2) + + iren.Start() + + +def read_polydata_(path): + """ + Read from a file containing vtkPolyData. + + If the path is empty a cone is returned. + If the extension is unknown a sphere is returned. + + :param path: The path to the file. + :return: The vtkPolyData. + """ + + poly_data = vtkPolyData() + + if path is None: + # Default to a cone if the path is empty. + source = vtkConeSource() + source.SetResolution(25) + source.SetDirection(0, 1, 0) + source.SetHeight(1) + source.Update() + poly_data.DeepCopy(source.GetOutput()) + return poly_data + + valid_suffixes = ['.g', '.obj', '.stl', '.ply', '.vtk', '.vtp'] + ext = path.suffix.lower() + if path.suffix not in valid_suffixes: + print('Warning:', path, 'unknown extension, using a sphere instead.') + source = vtkSphereSource() + source.SetPhiResolution(50) + source.SetThetaResolution(50) + source.Update() + poly_data.DeepCopy(source.GetOutput()) + else: + if ext == '.ply': + reader = vtkPLYReader() + reader.SetFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + elif ext == '.vtp': + reader = vtkXMLPolyDataReader() + reader.SetFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + elif ext == '.obj': + reader = vtkOBJReader() + reader.SetFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + elif ext == '.stl': + reader = vtkSTLReader() + reader.SetFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + elif ext == '.vtk': + reader = vtkPolyDataReader() + reader.SetFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + elif ext == '.g': + reader = vtkBYUReader() + reader.SetGeometryFileName(file_name) + reader.Update() + poly_data.DeepCopy(reader.GetOutput()) + + return poly_data + + +def viewport_border(renderer, sides, border_color, border_width): + """ + Set a border around a viewport. + + :param renderer: The renderer corresponding to the viewport. + :param sides: An array of boolean corresponding to [top, left, bottom, right] + :param border_color: The color of the border. + :param border_width: The width of the border. + :return: + """ + colors = vtkNamedColors() + + # Points start at upper right and proceed anti-clockwise. + points = vtkPoints() + points.SetNumberOfPoints(4) + points.InsertPoint(0, 1, 1, 0) + points.InsertPoint(1, 0, 1, 0) + points.InsertPoint(2, 0, 0, 0) + points.InsertPoint(3, 1, 0, 0) + + cells = vtkCellArray() + cells.Initialize() + + if sides[0]: + # Top + top = vtkPolyLine() + top.GetPointIds().SetNumberOfIds(2) + top.GetPointIds().SetId(0, 0) + top.GetPointIds().SetId(1, 1) + cells.InsertNextCell(top) + if sides[1]: + # Left + left = vtkPolyLine() + left.GetPointIds().SetNumberOfIds(2) + left.GetPointIds().SetId(0, 1) + left.GetPointIds().SetId(1, 2) + cells.InsertNextCell(left) + if sides[2]: + # Bottom + bottom = vtkPolyLine() + bottom.GetPointIds().SetNumberOfIds(2) + bottom.GetPointIds().SetId(0, 2) + bottom.GetPointIds().SetId(1, 3) + cells.InsertNextCell(bottom) + if sides[3]: + # Right + right = vtkPolyLine() + right.GetPointIds().SetNumberOfIds(2) + right.GetPointIds().SetId(0, 3) + right.GetPointIds().SetId(1, 0) + cells.InsertNextCell(right) + + # Now make the polydata and display it. + poly = vtkPolyData() + poly.Initialize() + poly.SetPoints(points) + poly.SetLines(cells) + + # Use normalized viewport coordinates since + # they are independent of window size. + coordinate = vtkCoordinate() + coordinate.SetCoordinateSystemToNormalizedViewport() + + mapper = vtkPolyDataMapper2D() + mapper.SetInputData(poly) + mapper.SetTransformCoordinate(coordinate) + + actor = vtkActor2D() + actor.SetMapper(mapper) + actor.GetProperty().SetColor(colors.GetColor3d(border_color)) + + # Line width should be at least 2 to be visible at extremes. + actor.GetProperty().SetLineWidth(border_width) + + renderer.AddViewProp(actor) + + +if __name__ == '__main__': + import sys + + file_name = get_program_parameters(sys.argv) + main(file_name) diff --git a/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png b/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..6ea9aca48256bd4f4e7b7a98eb95c8ecf72fdfdd --- /dev/null +++ b/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f98922c4356d7a3f80f5406ea4b047604c1c0c64c5ef0a693869802331358985 +size 292408 diff --git a/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png b/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..6ea9aca48256bd4f4e7b7a98eb95c8ecf72fdfdd --- /dev/null +++ b/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f98922c4356d7a3f80f5406ea4b047604c1c0c64c5ef0a693869802331358985 +size 292408 diff --git a/src/Testing/Data/star-wars-vader-tie-fighter.obj b/src/Testing/Data/star-wars-vader-tie-fighter.obj new file mode 100644 index 0000000000000000000000000000000000000000..2eb7df21a4445ee6337774dffe5f6e2732f14b73 --- /dev/null +++ b/src/Testing/Data/star-wars-vader-tie-fighter.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:595637d02489497885078e60990ee311e70e699882fac1ab7bf3ac2d2f729947 +size 11433883