diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index e31c49153..eca2f61bf 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-13, macos-12] + os: [macos-14, macos-13, macos-12] build_type: [Debug, Release] runs-on: ${{ matrix.os }} @@ -33,33 +33,42 @@ jobs: - name: Install dependencies run: | - brew install vtk wxmac - echo "MACOS_QT5_HINT=$(brew --prefix qt5)" >> $GITHUB_ENV + brew install vtk wxwidgets + echo "MACOS_QT5_HINT=$(brew --prefix qt@5)" >> $GITHUB_ENV - name: Create Build Environment run: cmake -E make_directory ${{runner.workspace}}/build - - name: Configure CMake + - name: Configure CMake (macOS 12, 13) + if: ${{ (matrix.os == 'macos-12') || (matrix.os == 'macos-13') }} shell: bash working-directory: ${{runner.workspace}}/build run: | cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_PREFIX_PATH=${{ env.MACOS_QT5_HINT }} + - name: Configure CMake (macOS 14) + if: matrix.os == 'macos-14' + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_PREFIX_PATH=${{ env.MACOS_QT5_HINT }} -DUSE_SSE=False + - name: Build shell: bash working-directory: ${{runner.workspace}}/build run: cmake --build . --config ${{matrix.build_type}} - name: Test (with OpenCL) - if: matrix.build_type == 'Release' + if: ${{ (matrix.build_type == 'Release') && (matrix.os != 'macos-14') }} # Run the full suite of tests since OpenCL is available + # Since macOS 14, OpenCL is no longer supported. :( shell: bash working-directory: ${{runner.workspace}}/build - run: ctest -C ${{matrix.build_type}} + run: ctest --output-on-failure -C ${{matrix.build_type}} - name: Test (without OpenCL) - if: matrix.build_type == 'Debug' + if: ${{ (matrix.build_type == 'Debug') || (matrix.os == 'macos-14') }} # Run a restricted suite of tests (OpenCL is available but the tests are slow on Debug) shell: bash working-directory: ${{runner.workspace}}/build - run: ctest -R rdy -C ${{matrix.build_type}} + run: ctest --output-on-failure -R rdy -C ${{matrix.build_type}} diff --git a/.github/workflows/build_ubuntu.yml b/.github/workflows/build_ubuntu.yml index 11be2b2bb..5e93df340 100644 --- a/.github/workflows/build_ubuntu.yml +++ b/.github/workflows/build_ubuntu.yml @@ -25,7 +25,14 @@ jobs: - name: git clone uses: actions/checkout@v4 - - name: Install dependencies + - name: Install dependencies (24.04) + if: matrix.os == 'ubuntu-24.04' + run: | + sudo apt-get update + sudo apt-get install libvtk9-dev ocl-icd-opencl-dev libgtk-3-dev libwxgtk3.2-dev libpocl2 qtbase5-dev qtdeclarative5-dev + + - name: Install dependencies (22.04, 20.04) + if: ${{ (matrix.os == 'ubuntu-22.04') || (matrix.os == 'ubuntu-20.04') }} run: | sudo apt-get update sudo apt-get install libvtk7-dev ocl-icd-opencl-dev libgtk-3-dev libwxgtk3.0-gtk3-dev libpocl2 diff --git a/BUILD.txt b/BUILD.txt index 46f2116f9..ce0c4de76 100644 --- a/BUILD.txt +++ b/BUILD.txt @@ -97,7 +97,9 @@ C) Build Ready: A) Dependencies: On Debian/Ubuntu: -sudo apt-get install libgtk-3-dev libxt-dev ocl-icd-opencl-dev libglu1-mesa-dev libvtk7-dev libwxgtk3.0-gtk3-dev cmake-curses-gui build-essential git +sudo apt-get install libgtk-3-dev libxt-dev ocl-icd-opencl-dev libglu1-mesa-dev libvtk9-dev libwxgtk3.2-dev cmake-curses-gui build-essential git + +(Or look at .github/workflows/build_ubuntu.yml) On Fedora: sudo dnf install vtk-devel wxGTK3-devel ocl-icd-devel opencl-headers gcc-c++ diff --git a/CMakeLists.txt b/CMakeLists.txt index 457686ad3..4b086a9ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2011-2021 The Ready Bunch +# Copyright 2011-2024 The Ready Bunch # # This file is part of Ready. # @@ -411,9 +411,9 @@ endif() #-------------------------------------------wxWidgets---------------------------------------------- if( APPLE ) - # on macOS it's best to use locally installed wxWidgets headers and libs - set( wxWidgets_CONFIG_EXECUTABLE /usr/local/bin/wx-config ) - set( wxWidgets_wxrc_EXECUTABLE /usr/local/bin/wxrc ) # not used, but no harm leaving it in + # on macOS you might want to to use locally installed wxWidgets headers and libs: + # set( wxWidgets_CONFIG_EXECUTABLE /usr/local/bin/wx-config ) + # set( wxWidgets_wxrc_EXECUTABLE /usr/local/bin/wxrc ) # not used, but no harm leaving it in elseif(UNIX) # remove -rdynamic from link options on Linux to reduce size by about 1.2MB set( CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "" ) @@ -448,17 +448,9 @@ else() ENDIF(VTK_USE_COCOA) else() find_package(PkgConfig) - if("-lwx_gtk2u_core-3.0" IN_LIST wxWidgets_LIBRARIES) - pkg_check_modules(GTK2 REQUIRED gtk+-2.0) - include_directories(${GTK2_INCLUDE_DIRS}) - link_libraries(${GTK2_LIBRARIES}) - elseif("-lwx_gtk3u_core-3.0" IN_LIST wxWidgets_LIBRARIES) - pkg_check_modules(GTK3 REQUIRED gtk+-3.0) - include_directories(${GTK3_INCLUDE_DIRS}) - link_libraries(${GTK3_LIBRARIES}) - else() - message(FATAL_ERROR "Didn't find -lwx_gtk2u_core-3.0 or -lwx_gtk3u_core-3.0 in wxWidgets_LIBRARIES - unable to detect GTK version to use: ${wxWidgets_LIBRARIES}") - endif() + pkg_check_modules(GTK3 REQUIRED gtk+-3.0) + include_directories(${GTK3_INCLUDE_DIRS}) + link_libraries(${GTK3_LIBRARIES}) endif() endif() diff --git a/Help/about.html b/Help/about.html index 499d952e0..e3c1cd6ee 100644 --- a/Help/about.html +++ b/Help/about.html @@ -7,7 +7,7 @@

Ready, version 0.11.0
-
Copyright 2011-2021 The Ready Bunch:
+
Copyright 2011-2024 The Ready Bunch:
Tim Hutton, Robert Munafo, Andrew Trevorrow,
Tom Rokicki, Dan Wills.


diff --git a/README.md b/README.md index ec6319c75..b36ea6554 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Ready supports 1D, 2D and 3D data, as well as polygonal and polyhedral meshes. Linux: ``` -sudo apt-get install libgtk-3-dev libxt-dev ocl-icd-opencl-dev libglu1-mesa-dev libvtk7-dev libwxgtk3.0-gtk3-dev cmake-curses-gui build-essential git +sudo apt-get install libgtk-3-dev libxt-dev ocl-icd-opencl-dev libglu1-mesa-dev libvtk9-dev libwxgtk3.2-dev cmake-curses-gui build-essential git git clone https://github.com/GollyGang/ready.git cd ready cmake -DCMAKE_BUILD_TYPE=Release . diff --git a/README.txt b/README.txt index 9c9572e4c..9703555ce 100644 --- a/README.txt +++ b/README.txt @@ -15,7 +15,7 @@ See Help/credits.html for a list of credits and acknowledgements. License --------------------------------------------------------------------------------- -Copyright 2011-2021 The Ready Bunch +Copyright 2011-2024 The Ready Bunch The Ready Bunch is: Tim Hutton, Robert Munafo, Andrew Trevorrow, Tom Rokicki, Dan Wills diff --git a/resources/Info.plist.in b/resources/Info.plist.in index 584eaa45b..e6378b150 100644 --- a/resources/Info.plist.in +++ b/resources/Info.plist.in @@ -23,7 +23,7 @@ CFBundleShortVersionString VERSION CFBundleGetInfoString - Ready version VERSION, Copyright 2011-2021 The Ready Bunch + Ready version VERSION, Copyright 2011-2024 The Ready Bunch LSRequiresCarbon NSRequiresAquaSystemAppearance diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index af7b4f3be..5416509a1 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/HelpPanel.cpp b/src/gui/HelpPanel.cpp index decdbe3cb..396a6464e 100644 --- a/src/gui/HelpPanel.cpp +++ b/src/gui/HelpPanel.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/HelpPanel.hpp b/src/gui/HelpPanel.hpp index ba440ee4f..2bf335802 100644 --- a/src/gui/HelpPanel.hpp +++ b/src/gui/HelpPanel.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/HtmlInfo.cpp b/src/gui/HtmlInfo.cpp index 98f7c10db..0e7555d2f 100644 --- a/src/gui/HtmlInfo.cpp +++ b/src/gui/HtmlInfo.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/HtmlInfo.hpp b/src/gui/HtmlInfo.hpp index a727d016e..0fc1d2b49 100644 --- a/src/gui/HtmlInfo.hpp +++ b/src/gui/HtmlInfo.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/IDs.hpp b/src/gui/IDs.hpp index 82d3a407d..faffe0685 100644 --- a/src/gui/IDs.hpp +++ b/src/gui/IDs.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/ImportImageDialog.cpp b/src/gui/ImportImageDialog.cpp index d28159a52..d07b72266 100644 --- a/src/gui/ImportImageDialog.cpp +++ b/src/gui/ImportImageDialog.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/ImportImageDialog.hpp b/src/gui/ImportImageDialog.hpp index 08e72006c..e347dc51e 100644 --- a/src/gui/ImportImageDialog.hpp +++ b/src/gui/ImportImageDialog.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/InfoPanel.cpp b/src/gui/InfoPanel.cpp index 0467520e7..3c9c3ee70 100644 --- a/src/gui/InfoPanel.cpp +++ b/src/gui/InfoPanel.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/InfoPanel.hpp b/src/gui/InfoPanel.hpp index 5919d3a72..d019710af 100644 --- a/src/gui/InfoPanel.hpp +++ b/src/gui/InfoPanel.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/InteractorStylePainter.cpp b/src/gui/InteractorStylePainter.cpp index 2470eae03..679342bdb 100644 --- a/src/gui/InteractorStylePainter.cpp +++ b/src/gui/InteractorStylePainter.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/InteractorStylePainter.hpp b/src/gui/InteractorStylePainter.hpp index 43f01a52a..813d0e711 100644 --- a/src/gui/InteractorStylePainter.hpp +++ b/src/gui/InteractorStylePainter.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/MakeNewSystem.cpp b/src/gui/MakeNewSystem.cpp index 24c63d825..73de98ef2 100644 --- a/src/gui/MakeNewSystem.cpp +++ b/src/gui/MakeNewSystem.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/MakeNewSystem.hpp b/src/gui/MakeNewSystem.hpp index 7dfd882a1..2dbf21582 100644 --- a/src/gui/MakeNewSystem.hpp +++ b/src/gui/MakeNewSystem.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/PatternsPanel.cpp b/src/gui/PatternsPanel.cpp index bb91773d6..1eccecc7c 100644 --- a/src/gui/PatternsPanel.cpp +++ b/src/gui/PatternsPanel.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/PatternsPanel.hpp b/src/gui/PatternsPanel.hpp index b968c218e..9b53c64af 100644 --- a/src/gui/PatternsPanel.hpp +++ b/src/gui/PatternsPanel.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/RecordingDialog.cpp b/src/gui/RecordingDialog.cpp index b4fabcd46..a07a8f96e 100644 --- a/src/gui/RecordingDialog.cpp +++ b/src/gui/RecordingDialog.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/RecordingDialog.hpp b/src/gui/RecordingDialog.hpp index 1978bc191..b2e6fd8cb 100644 --- a/src/gui/RecordingDialog.hpp +++ b/src/gui/RecordingDialog.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/app.cpp b/src/gui/app.cpp index 7b5040a10..17fa9cd67 100644 --- a/src/gui/app.cpp +++ b/src/gui/app.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/app.hpp b/src/gui/app.hpp index 7c7745b93..405c97801 100644 --- a/src/gui/app.hpp +++ b/src/gui/app.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/dialogs.cpp b/src/gui/dialogs.cpp index a46405ec8..1c2ccc97a 100644 --- a/src/gui/dialogs.cpp +++ b/src/gui/dialogs.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/dialogs.hpp b/src/gui/dialogs.hpp index e2ae43a73..3f677ee18 100644 --- a/src/gui/dialogs.hpp +++ b/src/gui/dialogs.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index efd9db4ea..3d246209a 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. @@ -327,7 +327,7 @@ MyFrame::MyFrame(const wxString& title) s->SetModified(false); s->SetFilename("untitled"); s->GenerateInitialPattern(); - this->SetCurrentRDSystem(move(s)); + this->SetCurrentRDSystem(std::move(s)); } } @@ -988,7 +988,7 @@ void MyFrame::OnAddMyPatterns(wxCommandEvent& event) void MyFrame::SetCurrentRDSystem(unique_ptr sys) { - this->system = move(sys); + this->system = std::move(sys); int iChem = IndexFromChemicalName(this->render_settings.GetProperty("active_chemical").GetChemical()); iChem = min(iChem,this->system->GetNumberOfChemicals()-1); // ensure is in valid range this->render_settings.GetProperty("active_chemical").SetChemical(GetChemicalName(iChem)); @@ -1608,7 +1608,7 @@ void MyFrame::OnNewPattern(wxCommandEvent& event) this->SetStatusText(_("Generating data values...")); sys->CreateDefaultInitialPatternGenerator(sys->GetNumberOfChemicals()); sys->GenerateInitialPattern(); - this->SetCurrentRDSystem(move(sys)); + this->SetCurrentRDSystem(std::move(sys)); this->system->SetFilename("untitled"); this->system->SetModified(false); @@ -1680,7 +1680,7 @@ void MyFrame::OpenFile(const wxString& raw_path, bool remember) SetDefaultRenderSettings(this->render_settings); target_system = SystemFactory::CreateFromFile(path.mb_str(),this->is_opencl_available,opencl_platform,opencl_device,this->render_settings,warn_to_update); this->patterns_panel->SelectPath(path); - this->SetCurrentRDSystem(move(target_system)); + this->SetCurrentRDSystem(std::move(target_system)); } catch(const exception& e) { @@ -2715,7 +2715,7 @@ void MyFrame::MakeDefaultImageSystemFromMesh(vtkUnstructuredGrid* ug) image_sys->CreateDefaultInitialPatternGenerator(2); image_sys->GenerateInitialPattern(); this->render_settings.GetProperty("timesteps_per_render").SetInt(16); - this->SetCurrentRDSystem(move(image_sys)); + this->SetCurrentRDSystem(std::move(image_sys)); } // --------------------------------------------------------------------- @@ -2734,7 +2734,7 @@ void MyFrame::MakeDefaultMeshSystemFromMesh(vtkUnstructuredGrid* ug) mesh_sys->SetNumberOfChemicals(2); mesh_sys->CreateDefaultInitialPatternGenerator(2); mesh_sys->GenerateInitialPattern(); - this->SetCurrentRDSystem(move(mesh_sys)); + this->SetCurrentRDSystem(std::move(mesh_sys)); } // --------------------------------------------------------------------- @@ -3515,7 +3515,7 @@ void MyFrame::OnConvertToFullKernel(wxCommandEvent& event) wxMessageBox(wxString::Format(_T("Error converting rule: %s"),e.what())); return; } - this->SetCurrentRDSystem(move(sys)); + this->SetCurrentRDSystem(std::move(sys)); } // --------------------------------------------------------------------- diff --git a/src/gui/frame.hpp b/src/gui/frame.hpp index d5623e3f9..e82e54d3a 100644 --- a/src/gui/frame.hpp +++ b/src/gui/frame.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/prefs.cpp b/src/gui/prefs.cpp index 8396d62f6..a8d3b255b 100644 --- a/src/gui/prefs.cpp +++ b/src/gui/prefs.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/prefs.hpp b/src/gui/prefs.hpp index c28687a89..f4f213db1 100644 --- a/src/gui/prefs.hpp +++ b/src/gui/prefs.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/vtk_pipeline.cpp b/src/gui/vtk_pipeline.cpp index 431df29b0..111f3135d 100644 --- a/src/gui/vtk_pipeline.cpp +++ b/src/gui/vtk_pipeline.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/vtk_pipeline.hpp b/src/gui/vtk_pipeline.hpp index f3ec7dc96..f92e890a4 100644 --- a/src/gui/vtk_pipeline.hpp +++ b/src/gui/vtk_pipeline.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/wxutils.cpp b/src/gui/wxutils.cpp index 6a129ea60..cde6aa339 100644 --- a/src/gui/wxutils.cpp +++ b/src/gui/wxutils.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/gui/wxutils.hpp b/src/gui/wxutils.hpp index f502c1186..3ab7be55a 100644 --- a/src/gui/wxutils.hpp +++ b/src/gui/wxutils.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/AbstractRD.cpp b/src/readybase/AbstractRD.cpp index 9789abfe8..abe7d9175 100644 --- a/src/readybase/AbstractRD.cpp +++ b/src/readybase/AbstractRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. @@ -23,7 +23,9 @@ #include // SSE: +#if USE_SSE #include +#endif using namespace std; diff --git a/src/readybase/AbstractRD.hpp b/src/readybase/AbstractRD.hpp index 050f4c792..9f795e8fa 100644 --- a/src/readybase/AbstractRD.hpp +++ b/src/readybase/AbstractRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FormulaOpenCLImageRD.cpp b/src/readybase/FormulaOpenCLImageRD.cpp index 1226d37c4..e34500ad7 100644 --- a/src/readybase/FormulaOpenCLImageRD.cpp +++ b/src/readybase/FormulaOpenCLImageRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FormulaOpenCLImageRD.hpp b/src/readybase/FormulaOpenCLImageRD.hpp index 828852afd..ef379d939 100644 --- a/src/readybase/FormulaOpenCLImageRD.hpp +++ b/src/readybase/FormulaOpenCLImageRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FormulaOpenCLMeshRD.cpp b/src/readybase/FormulaOpenCLMeshRD.cpp index 7e5f113ef..5a8b22bdc 100644 --- a/src/readybase/FormulaOpenCLMeshRD.cpp +++ b/src/readybase/FormulaOpenCLMeshRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FormulaOpenCLMeshRD.hpp b/src/readybase/FormulaOpenCLMeshRD.hpp index f76ec2ce7..89ec3f272 100644 --- a/src/readybase/FormulaOpenCLMeshRD.hpp +++ b/src/readybase/FormulaOpenCLMeshRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FullKernelOpenCLImageRD.cpp b/src/readybase/FullKernelOpenCLImageRD.cpp index a3ed0fbf5..dd70fb5ee 100644 --- a/src/readybase/FullKernelOpenCLImageRD.cpp +++ b/src/readybase/FullKernelOpenCLImageRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FullKernelOpenCLImageRD.hpp b/src/readybase/FullKernelOpenCLImageRD.hpp index 5be5650a6..7681403ff 100644 --- a/src/readybase/FullKernelOpenCLImageRD.hpp +++ b/src/readybase/FullKernelOpenCLImageRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FullKernelOpenCLMeshRD.cpp b/src/readybase/FullKernelOpenCLMeshRD.cpp index 8fce537bc..c0273ee18 100644 --- a/src/readybase/FullKernelOpenCLMeshRD.cpp +++ b/src/readybase/FullKernelOpenCLMeshRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/FullKernelOpenCLMeshRD.hpp b/src/readybase/FullKernelOpenCLMeshRD.hpp index 59e58249c..495ace51c 100644 --- a/src/readybase/FullKernelOpenCLMeshRD.hpp +++ b/src/readybase/FullKernelOpenCLMeshRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/GrayScottImageRD.cpp b/src/readybase/GrayScottImageRD.cpp index b1446ae6e..5739a2dd7 100644 --- a/src/readybase/GrayScottImageRD.cpp +++ b/src/readybase/GrayScottImageRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/GrayScottImageRD.hpp b/src/readybase/GrayScottImageRD.hpp index 131eac5f9..944cff00b 100644 --- a/src/readybase/GrayScottImageRD.hpp +++ b/src/readybase/GrayScottImageRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/GrayScottMeshRD.cpp b/src/readybase/GrayScottMeshRD.cpp index 5399f7556..57ad13179 100644 --- a/src/readybase/GrayScottMeshRD.cpp +++ b/src/readybase/GrayScottMeshRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/GrayScottMeshRD.hpp b/src/readybase/GrayScottMeshRD.hpp index 4c246e40f..1d3f90b52 100644 --- a/src/readybase/GrayScottMeshRD.hpp +++ b/src/readybase/GrayScottMeshRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/IO_XML.cpp b/src/readybase/IO_XML.cpp index bd6472a2f..1323ae3c2 100644 --- a/src/readybase/IO_XML.cpp +++ b/src/readybase/IO_XML.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/IO_XML.hpp b/src/readybase/IO_XML.hpp index 484359130..b486d921d 100644 --- a/src/readybase/IO_XML.hpp +++ b/src/readybase/IO_XML.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/ImageRD.cpp b/src/readybase/ImageRD.cpp index 9920b4bc3..e3bcf07b9 100644 --- a/src/readybase/ImageRD.cpp +++ b/src/readybase/ImageRD.cpp @@ -1,1711 +1,1720 @@ -/* Copyright 2011-2021 The Ready Bunch - - This file is part of Ready. - - Ready is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Ready is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Ready. If not, see . */ - -// local: -#include "ImageRD.hpp" -#include "IO_XML.hpp" -#include "overlays.hpp" -#include "Properties.hpp" -#include "scene_items.hpp" -#include "utils.hpp" - -// STL: -#include -#include -#include - -// VTK: -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -// ------------------------------------------------------------------- - -ImageRD::ImageRD(int data_type) - : AbstractRD(data_type) - , image_top1D(2.0) - , image_ratio1D(30.0) -{ - this->starting_pattern = vtkSmartPointer::New(); - this->assign_attribute_filter = NULL; - this->rearrange_fields_filter = NULL; -} - -// --------------------------------------------------------------------- - -ImageRD::~ImageRD() -{ - this->DeallocateImages(); -} - -// --------------------------------------------------------------------- - -void ImageRD::DeallocateImages() -{ - this->images.clear(); - this->n_chemicals = 0; -} - -// --------------------------------------------------------------------- - -int ImageRD::GetArenaDimensionality() const -{ - assert(this->images.front()); - int dimensionality=0; - for(int iDim=0;iDim<3;iDim++) - if(this->images.front()->GetDimensions()[iDim]>1) - dimensionality++; - return dimensionality; -} - -// --------------------------------------------------------------------- - -float ImageRD::GetX() const -{ - return this->images.front()->GetDimensions()[0]; -} - -// --------------------------------------------------------------------- - -float ImageRD::GetY() const -{ - return this->images.front()->GetDimensions()[1]; -} - -// --------------------------------------------------------------------- - -float ImageRD::GetZ() const -{ - return this->images.front()->GetDimensions()[2]; -} - -// --------------------------------------------------------------------- - -vtkImageData* ImageRD::GetImage(int iChemical) const -{ - return this->images[iChemical]; -} - -// --------------------------------------------------------------------- - -void ImageRD::GetImage(vtkImageData *im) const -{ - vtkSmartPointer iac = vtkSmartPointer::New(); - for(int i=0;iGetNumberOfChemicals();i++) - { - iac->AddInputData(this->GetImage(i)); - } - iac->Update(); - im->DeepCopy(iac->GetOutput()); -} - -// --------------------------------------------------------------------- - -void ImageRD::CopyFromImage(vtkImageData* im) -{ - int n_arrays = im->GetPointData()->GetNumberOfArrays(); - int n_components = im->GetNumberOfScalarComponents(); - - bool has_named_arrays = true; - for(int iChem=0;iChemGetNumberOfChemicals();iChem++) - { - if(!im->GetPointData()->HasArray(GetChemicalName(iChem).c_str())) - { - has_named_arrays = false; - break; - } - } - - if(has_named_arrays && n_components==1 && n_arrays==this->GetNumberOfChemicals()) - { - // convert named array data to single-component data in multiple images - for(int iChem=0;iChemGetNumberOfChemicals();iChem++) - { - this->images[iChem]->SetExtent(im->GetExtent()); - this->images[iChem]->GetPointData()->SetScalars(im->GetPointData()->GetArray(GetChemicalName(iChem).c_str())); - } - } - else if(n_arrays==1 && n_components==this->GetNumberOfChemicals()) - { - // convert multi-component data to single-component data in multiple images - vtkSmartPointer iec = vtkSmartPointer::New(); - iec->SetInputData(im); - for(int i=0;iGetNumberOfChemicals();i++) - { - iec->SetComponents(i); - iec->Update(); - this->images[i]->DeepCopy(iec->GetOutput()); - } - } - else - throw runtime_error("ImageRD::CopyFromImage : chemical count mismatch"); - - this->undo_stack.clear(); -} - -// --------------------------------------------------------------------- - -void ImageRD::CopyFromMesh( - vtkUnstructuredGrid* mesh, - const int num_chemicals, - const size_t target_chemical, - const size_t largest_dimension, - const float value_inside, - const float value_outside) -{ - // decide the size of the image - mesh->ComputeBounds(); - double bounds[6]; - mesh->GetBounds(bounds); - const double mesh_size[3] = { bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4] }; - const float max_mesh_size = std::max(mesh_size[0], std::max(mesh_size[1], mesh_size[2])); - const float scale = (largest_dimension-1) / max_mesh_size; - int image_size[3]; - for(size_t xyz = 0; xyz < 3; ++xyz) - { - image_size[xyz] = 1; - while( image_size[xyz] < mesh_size[xyz] * scale ) - { - image_size[xyz] <<= 1; - } - } - AllocateImages(image_size[0], image_size[1], image_size[2], num_chemicals, this->GetDataType()); - BlankImage(value_outside); - - // write data into the image - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PostMultiply(); - transform->Translate(-(bounds[0] + bounds[1]) / 2.0, -(bounds[2] + bounds[3]) / 2.0, -(bounds[4] + bounds[5]) / 2.0); // center at origin - transform->Scale(scale, scale, scale); - transform->Translate(image_size[0] / 2, image_size[1] / 2, image_size[2] / 2); // center in volume - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); - transform_filter->SetInputData(mesh); - vtkSmartPointer get_surface = vtkSmartPointer::New(); - get_surface->SetInputConnection(transform_filter->GetOutputPort()); - vtkSmartPointer pol2stenc = vtkSmartPointer::New(); - pol2stenc->SetInputConnection(get_surface->GetOutputPort()); - vtkSmartPointer imgstenc = vtkSmartPointer::New(); - imgstenc->SetInputData(this->images[target_chemical]); - imgstenc->SetStencilConnection(pol2stenc->GetOutputPort()); - imgstenc->ReverseStencilOn(); - imgstenc->SetBackgroundValue(value_inside); - imgstenc->Update(); - this->images[target_chemical]->DeepCopy(imgstenc->GetOutput()); -} - -// --------------------------------------------------------------------- - -void ImageRD::AllocateImages(int x,int y,int z,int nc,int data_type) -{ - this->DeallocateImages(); - this->n_chemicals = nc; - this->images.resize(nc); - for(int i=0;iimages[i] = AllocateVTKImage(x,y,z,data_type); - this->is_modified = true; - this->undo_stack.clear(); -} - -// --------------------------------------------------------------------- - -/* static */ vtkSmartPointer ImageRD::AllocateVTKImage(int x,int y,int z,int data_type) -{ - vtkSmartPointer im = vtkSmartPointer::New(); - im->SetDimensions(x,y,z); - im->AllocateScalars(data_type,1); - if(im->GetDimensions()[0]!=x || im->GetDimensions()[1]!=y || im->GetDimensions()[2]!=z) - throw runtime_error("ImageRD::AllocateVTKImage : Failed to allocate image data - dimensions too big?"); - return im; -} - -// --------------------------------------------------------------------- - -void ImageRD::GenerateInitialPattern() -{ - if (this->initial_pattern_generator.ShouldZeroFirst()) { - this->BlankImage(); - } - - const int X = this->images.front()->GetDimensions()[0]; - const int Y = this->images.front()->GetDimensions()[1]; - const int Z = this->images.front()->GetDimensions()[2]; - - for (size_t iOverlay = 0; iOverlay < this->initial_pattern_generator.GetNumberOfOverlays(); iOverlay++) - { - this->initial_pattern_generator.GetOverlay(iOverlay).Reseed(); - } - - for(int z=0;zinitial_pattern_generator.GetNumberOfOverlays(); iOverlay++) - { - const Overlay& overlay = this->initial_pattern_generator.GetOverlay(iOverlay); - - int iC = overlay.GetTargetChemical(); - if(iC<0 || iC>=this->GetNumberOfChemicals()) - continue; // best for now to silently ignore this overlay, because the user has no way of editing the overlays (short of editing the file) - //throw runtime_error("Overlay: chemical out of range: "+GetChemicalName(iC)); - - vector vals(this->GetNumberOfChemicals()); - for(int i=0;iGetNumberOfChemicals();i++) - vals[i] = this->GetImage(i)->GetScalarComponentAsDouble(x,y,z,0); - this->GetImage(iC)->SetScalarComponentFromDouble(x, y, z, 0, overlay.Apply(vals, *this, x, y, z)); - } - } - } - } - for(int i=0;i<(int)this->images.size();i++) - this->images[i]->Modified(); - this->timesteps_taken = 0; -} - -// --------------------------------------------------------------------- - -void ImageRD::BlankImage(float value) -{ - for(int iImage=0;iImage<(int)this->images.size();iImage++) - { - this->images[iImage]->GetPointData()->GetScalars()->FillComponent(0, value); - this->images[iImage]->Modified(); - } - this->timesteps_taken = 0; - this->undo_stack.clear(); -} - -// --------------------------------------------------------------------- - -void ImageRD::Update(int n_steps) -{ - this->undo_stack.clear(); - this->InternalUpdate(n_steps); - - this->timesteps_taken += n_steps; - - for(int ic=0;icGetNumberOfChemicals();ic++) - this->images[ic]->Modified(); - - if(this->rearrange_fields_filter && this->assign_attribute_filter) - { - // manually update the rendering pipeline to allow for changing array names - // TODO: this step shouldn't be necessary - this->rearrange_fields_filter->Update(); - assign_attribute_filter->Assign(this->rearrange_fields_filter->GetOutput()->GetCellData()->GetArray(0)->GetName(), - vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::InitializeRenderPipeline(vtkRenderer* pRenderer,const Properties& render_settings) -{ - this->rearrange_fields_filter = NULL; - this->assign_attribute_filter = NULL; - - switch(this->GetArenaDimensionality()) - { - // TODO: merge the dimensionalities (often want one/more slices from lower dimensionalities) - case 0: - case 1: this->InitializeVTKPipeline_1D(pRenderer,render_settings); break; - case 2: this->InitializeVTKPipeline_2D(pRenderer,render_settings); break; - case 3: this->InitializeVTKPipeline_3D(pRenderer,render_settings); break; - default: - throw runtime_error("ImageRD::InitializeRenderPipeline : Unsupported dimensionality"); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::InitializeVTKPipeline_1D(vtkRenderer* pRenderer,const Properties& render_settings) -{ - float low = render_settings.GetProperty("low").GetFloat(); - float high = render_settings.GetProperty("high").GetFloat(); - float vertical_scale_1D = render_settings.GetProperty("vertical_scale_1D").GetFloat(); - bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); - int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); - bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); - bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); - bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); - int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); - int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); - int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); - bool plot_ab_orthogonally = render_settings.GetProperty("plot_ab_orthogonally").GetBool(); - if (plot_ab_orthogonally && this->GetNumberOfChemicals() <= 1) - { - plot_ab_orthogonally = false; - } - - int iFirstChem = 0; - int iLastChem = this->GetNumberOfChemicals() - 1; - if(!show_multiple_chemicals) - { - if (plot_ab_orthogonally && iActiveChemical < 2) - { - iFirstChem = 0; - iLastChem = 1; - } - else - { - iFirstChem = iActiveChemical; - iLastChem = iFirstChem; - } - } - - float scaling = vertical_scale_1D / (high-low); // vertical_scale gives the height of the graph in worldspace units - const float image_height = this->GetX() / this->image_ratio1D; // we thicken it - const float y_gap = image_height; - - vtkSmartPointer lut = GetColorMap(render_settings); - - for(int iChem = iFirstChem; iChem <= iLastChem; ++iChem) - { - // pass the image through the lookup table - vtkSmartPointer image_mapper = vtkSmartPointer::New(); - image_mapper->SetLookupTable(lut); - image_mapper->SetInputData(this->GetImage(iChem)); - - // will convert the x*y 2D image to a x*y grid of quads - const float image_offset = this->image_top1D - image_height * 2.0f * (iChem - iFirstChem); - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetXResolution(this->GetX()); - plane->SetYResolution(this->GetY()); - plane->SetOrigin(0,image_offset-image_height,0); - plane->SetPoint1(this->GetX(),image_offset-image_height,0); - plane->SetPoint2(0,image_offset,0); - - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(image_mapper->GetOutputPort()); - if(use_image_interpolation) - texture->InterpolateOn(); - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(plane->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->SetTexture(texture); - if(show_cell_edges) - actor->GetProperty()->EdgeVisibilityOn(); - actor->GetProperty()->SetEdgeColor(0,0,0); - actor->GetProperty()->LightingOff(); - pRenderer->AddActor(actor); - - // add a text label - if(show_chemical_label && this->GetNumberOfChemicals()>1) - { - vtkSmartPointer captionActor = vtkSmartPointer::New(); - captionActor->SetAttachmentPoint(-image_height, image_offset - image_height/2, 0); - captionActor->SetPosition(0, 0); - captionActor->SetCaption(GetChemicalName(iChem).c_str()); - captionActor->BorderOff(); - captionActor->LeaderOff(); - captionActor->SetPadding(0); - captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); - captionActor->GetCaptionTextProperty()->BoldOff(); - captionActor->GetCaptionTextProperty()->ShadowOff(); - captionActor->GetCaptionTextProperty()->ItalicOff(); - captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); - captionActor->GetCaptionTextProperty()->SetFontSize(16); - captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); - captionActor->GetTextActor()->SetTextScaleModeToNone(); - pRenderer->AddActor(captionActor); - } - } - - // also add a scalar bar to show how the colors correspond to values - if(show_color_scale) - { - AddScalarBar(pRenderer,lut); - } - - // add a line graph for all the chemicals (active one highlighted) - const float graph_bottom = this->image_top1D + y_gap; - const float graph_top = graph_bottom + (high-low) * scaling; - for(int iChemical = iFirstChem; iChemical <= iLastChem; iChemical++) - { - if (plot_ab_orthogonally && iChemical == 1) - { - continue; - } - vtkSmartPointer mapper = vtkSmartPointer::New(); - vtkSmartPointer actor = vtkSmartPointer::New(); - if (plot_ab_orthogonally && iChemical == 0) - { - // plot the merged ab pair here - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetInputData(this->GetImage(0)); - vtkSmartPointer warp_y = vtkSmartPointer::New(); - warp_y->SetInputConnection(plane->GetOutputPort()); - warp_y->SetScaleFactor(scaling); - warp_y->SetNormal(0, 1, 0); - vtkSmartPointer plane2 = vtkSmartPointer::New(); - plane2->SetInputData(this->GetImage(1)); - vtkSmartPointer merge = vtkSmartPointer::New(); - merge->SetGeometryConnection(warp_y->GetOutputPort()); - merge->SetScalarsConnection(plane2->GetOutputPort()); - vtkSmartPointer warp_z = vtkSmartPointer::New(); - warp_z->SetInputConnection(merge->GetOutputPort()); - warp_z->SetScaleFactor(scaling); - warp_z->SetNormal(0, 0, -1); - vtkSmartPointer stripper = vtkSmartPointer::New(); - stripper->SetInputConnection(warp_z->GetOutputPort()); - vtkSmartPointer tube = vtkSmartPointer::New(); - tube->SetInputConnection(stripper->GetOutputPort()); - tube->SetRadius(this->GetX() / 512.0); - tube->SetNumberOfSides(6); - mapper->SetInputConnection(tube->GetOutputPort()); - actor->GetProperty()->SetColor(1, 1, 1); - actor->GetProperty()->SetAmbient(0.3); - } - else - { - // plot this chemical in the normal way - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetInputData(this->GetImage(iChemical)); - vtkSmartPointer warp = vtkSmartPointer::New(); - warp->SetInputConnection(plane->GetOutputPort()); - warp->SetScaleFactor(scaling); - warp->SetNormal(0, 1, 0); - mapper->SetInputConnection(warp->GetOutputPort()); - actor->GetProperty()->SetAmbient(1); - if (iChemical == iActiveChemical) - actor->GetProperty()->SetColor(1, 1, 1); - else - actor->GetProperty()->SetColor(0.5, 0.5, 0.5); - } - mapper->ScalarVisibilityOff(); - actor->SetMapper(mapper); - actor->PickableOff(); - actor->SetPosition(0, graph_bottom - low * scaling,0); - pRenderer->AddActor(actor); - } - - // add an axis - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(0,0,graph_bottom,graph_top,0,0); - axis->SetRanges(0,0,low,high,0,0); - axis->UseRangesOn(); - axis->XAxisVisibilityOff(); - axis->ZAxisVisibilityOff(); - axis->SetYLabel(""); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - if (plot_ab_orthogonally) - { - axis->SetYLabel("a"); - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(0, 0, graph_top, graph_top, -low * scaling, -high * scaling); - axis->SetRanges(0, 0, 0, 0, low, high); - axis->UseRangesOn(); - axis->XAxisVisibilityOff(); - axis->YAxisVisibilityOff(); - axis->SetZLabel("b"); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - } - - // add a phase plot - const float phase_plot_bottom = graph_top + y_gap*2; - if(show_phase_plot && this->GetNumberOfChemicals()>=2) - { - this->AddPhasePlot(pRenderer,scaling,low,high,0.0f, phase_plot_bottom,0.0f,iPhasePlotX,iPhasePlotY,iPhasePlotZ); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::InitializeVTKPipeline_2D(vtkRenderer* pRenderer,const Properties& render_settings) -{ - float low = render_settings.GetProperty("low").GetFloat(); - float high = render_settings.GetProperty("high").GetFloat(); - float vertical_scale_2D = render_settings.GetProperty("vertical_scale_2D").GetFloat(); - bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); - int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - bool use_wireframe = render_settings.GetProperty("use_wireframe").GetBool(); - float surface_r,surface_g,surface_b; - render_settings.GetProperty("surface_color").GetColor(surface_r,surface_g,surface_b); - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - bool show_displacement_mapped_surface = render_settings.GetProperty("show_displacement_mapped_surface").GetBool(); - bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); - bool color_displacement_mapped_surface = render_settings.GetProperty("color_displacement_mapped_surface").GetBool(); - bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); - bool show_bounding_box = render_settings.GetProperty("show_bounding_box").GetBool(); - bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); - bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); - int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); - int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); - int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); - - const float scaling = vertical_scale_2D / (high-low); // vertical_scale gives the height of the graph in worldspace units - const float x_gap = this->x_spacing_proportion * this->GetX(); - const float y_gap = this->y_spacing_proportion * this->GetY(); - - double offset[3] = {0,0,0}; - const float surface_bottom = offset[1] + 0.5 + this->GetY() + y_gap; - const float surface_top = surface_bottom + this->GetY(); - - int iFirstChem = 0; - int iLastChem = this->GetNumberOfChemicals() - 1; - if(!show_multiple_chemicals) { iFirstChem = iActiveChemical; iLastChem = iFirstChem; } - +/* Copyright 2011-2024 The Ready Bunch + + This file is part of Ready. + + Ready is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Ready is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Ready. If not, see . */ + +// local: +#include "ImageRD.hpp" +#include "IO_XML.hpp" +#include "overlays.hpp" +#include "Properties.hpp" +#include "scene_items.hpp" +#include "utils.hpp" + +// STL: +#include +#include +#include + +// VTK: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// ------------------------------------------------------------------- + +ImageRD::ImageRD(int data_type) + : AbstractRD(data_type) + , image_top1D(2.0) + , image_ratio1D(30.0) +{ + this->starting_pattern = vtkSmartPointer::New(); + this->assign_attribute_filter = NULL; + this->rearrange_fields_filter = NULL; +} + +// --------------------------------------------------------------------- + +ImageRD::~ImageRD() +{ + this->DeallocateImages(); +} + +// --------------------------------------------------------------------- + +void ImageRD::DeallocateImages() +{ + this->images.clear(); + this->n_chemicals = 0; +} + +// --------------------------------------------------------------------- + +int ImageRD::GetArenaDimensionality() const +{ + assert(this->images.front()); + int dimensionality=0; + for(int iDim=0;iDim<3;iDim++) + if(this->images.front()->GetDimensions()[iDim]>1) + dimensionality++; + return dimensionality; +} + +// --------------------------------------------------------------------- + +float ImageRD::GetX() const +{ + return this->images.front()->GetDimensions()[0]; +} + +// --------------------------------------------------------------------- + +float ImageRD::GetY() const +{ + return this->images.front()->GetDimensions()[1]; +} + +// --------------------------------------------------------------------- + +float ImageRD::GetZ() const +{ + return this->images.front()->GetDimensions()[2]; +} + +// --------------------------------------------------------------------- + +vtkImageData* ImageRD::GetImage(int iChemical) const +{ + return this->images[iChemical]; +} + +// --------------------------------------------------------------------- + +void ImageRD::GetImage(vtkImageData *im) const +{ + vtkSmartPointer iac = vtkSmartPointer::New(); + for(int i=0;iGetNumberOfChemicals();i++) + { + iac->AddInputData(this->GetImage(i)); + } + iac->Update(); + im->DeepCopy(iac->GetOutput()); +} + +// --------------------------------------------------------------------- + +void ImageRD::CopyFromImage(vtkImageData* im) +{ + int n_arrays = im->GetPointData()->GetNumberOfArrays(); + int n_components = im->GetNumberOfScalarComponents(); + + bool has_named_arrays = true; + for(int iChem=0;iChemGetNumberOfChemicals();iChem++) + { + if(!im->GetPointData()->HasArray(GetChemicalName(iChem).c_str())) + { + has_named_arrays = false; + break; + } + } + + if(has_named_arrays && n_components==1 && n_arrays==this->GetNumberOfChemicals()) + { + // convert named array data to single-component data in multiple images + for(int iChem=0;iChemGetNumberOfChemicals();iChem++) + { + this->images[iChem]->SetExtent(im->GetExtent()); + this->images[iChem]->GetPointData()->SetScalars(im->GetPointData()->GetArray(GetChemicalName(iChem).c_str())); + } + } + else if(n_arrays==1 && n_components==this->GetNumberOfChemicals()) + { + // convert multi-component data to single-component data in multiple images + vtkSmartPointer iec = vtkSmartPointer::New(); + iec->SetInputData(im); + for(int i=0;iGetNumberOfChemicals();i++) + { + iec->SetComponents(i); + iec->Update(); + this->images[i]->DeepCopy(iec->GetOutput()); + } + } + else + throw runtime_error("ImageRD::CopyFromImage : chemical count mismatch"); + + this->undo_stack.clear(); +} + +// --------------------------------------------------------------------- + +void ImageRD::CopyFromMesh( + vtkUnstructuredGrid* mesh, + const int num_chemicals, + const size_t target_chemical, + const size_t largest_dimension, + const float value_inside, + const float value_outside) +{ + // decide the size of the image + mesh->ComputeBounds(); + double bounds[6]; + mesh->GetBounds(bounds); + const double mesh_size[3] = { bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4] }; + const float max_mesh_size = std::max(mesh_size[0], std::max(mesh_size[1], mesh_size[2])); + const float scale = (largest_dimension-1) / max_mesh_size; + int image_size[3]; + for(size_t xyz = 0; xyz < 3; ++xyz) + { + image_size[xyz] = 1; + while( image_size[xyz] < mesh_size[xyz] * scale ) + { + image_size[xyz] <<= 1; + } + } + AllocateImages(image_size[0], image_size[1], image_size[2], num_chemicals, this->GetDataType()); + BlankImage(value_outside); + + // write data into the image + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->PostMultiply(); + transform->Translate(-(bounds[0] + bounds[1]) / 2.0, -(bounds[2] + bounds[3]) / 2.0, -(bounds[4] + bounds[5]) / 2.0); // center at origin + transform->Scale(scale, scale, scale); + transform->Translate(image_size[0] / 2, image_size[1] / 2, image_size[2] / 2); // center in volume + vtkSmartPointer transform_filter = vtkSmartPointer::New(); + transform_filter->SetTransform(transform); + transform_filter->SetInputData(mesh); + vtkSmartPointer get_surface = vtkSmartPointer::New(); + get_surface->SetInputConnection(transform_filter->GetOutputPort()); + vtkSmartPointer pol2stenc = vtkSmartPointer::New(); + pol2stenc->SetInputConnection(get_surface->GetOutputPort()); + vtkSmartPointer imgstenc = vtkSmartPointer::New(); + imgstenc->SetInputData(this->images[target_chemical]); + imgstenc->SetStencilConnection(pol2stenc->GetOutputPort()); + imgstenc->ReverseStencilOn(); + imgstenc->SetBackgroundValue(value_inside); + imgstenc->Update(); + this->images[target_chemical]->DeepCopy(imgstenc->GetOutput()); +} + +// --------------------------------------------------------------------- + +void ImageRD::AllocateImages(int x,int y,int z,int nc,int data_type) +{ + this->DeallocateImages(); + this->n_chemicals = nc; + this->images.resize(nc); + for(int i=0;iimages[i] = AllocateVTKImage(x,y,z,data_type); + this->is_modified = true; + this->undo_stack.clear(); +} + +// --------------------------------------------------------------------- + +/* static */ vtkSmartPointer ImageRD::AllocateVTKImage(int x,int y,int z,int data_type) +{ + vtkSmartPointer im = vtkSmartPointer::New(); + im->SetDimensions(x,y,z); + im->AllocateScalars(data_type,1); + if(im->GetDimensions()[0]!=x || im->GetDimensions()[1]!=y || im->GetDimensions()[2]!=z) + throw runtime_error("ImageRD::AllocateVTKImage : Failed to allocate image data - dimensions too big?"); + return im; +} + +// --------------------------------------------------------------------- + +void ImageRD::GenerateInitialPattern() +{ + if (this->initial_pattern_generator.ShouldZeroFirst()) { + this->BlankImage(); + } + + const int X = this->images.front()->GetDimensions()[0]; + const int Y = this->images.front()->GetDimensions()[1]; + const int Z = this->images.front()->GetDimensions()[2]; + + for (size_t iOverlay = 0; iOverlay < this->initial_pattern_generator.GetNumberOfOverlays(); iOverlay++) + { + this->initial_pattern_generator.GetOverlay(iOverlay).Reseed(); + } + + for(int z=0;zinitial_pattern_generator.GetNumberOfOverlays(); iOverlay++) + { + const Overlay& overlay = this->initial_pattern_generator.GetOverlay(iOverlay); + + int iC = overlay.GetTargetChemical(); + if(iC<0 || iC>=this->GetNumberOfChemicals()) + continue; // best for now to silently ignore this overlay, because the user has no way of editing the overlays (short of editing the file) + //throw runtime_error("Overlay: chemical out of range: "+GetChemicalName(iC)); + + vector vals(this->GetNumberOfChemicals()); + for(int i=0;iGetNumberOfChemicals();i++) + vals[i] = this->GetImage(i)->GetScalarComponentAsDouble(x,y,z,0); + this->GetImage(iC)->SetScalarComponentFromDouble(x, y, z, 0, overlay.Apply(vals, *this, x, y, z)); + } + } + } + } + for(int i=0;i<(int)this->images.size();i++) + this->images[i]->Modified(); + this->timesteps_taken = 0; +} + +// --------------------------------------------------------------------- + +void ImageRD::BlankImage(float value) +{ + for(int iImage=0;iImage<(int)this->images.size();iImage++) + { + this->images[iImage]->GetPointData()->GetScalars()->FillComponent(0, value); + this->images[iImage]->Modified(); + } + this->timesteps_taken = 0; + this->undo_stack.clear(); +} + +// --------------------------------------------------------------------- + +void ImageRD::Update(int n_steps) +{ + this->undo_stack.clear(); + this->InternalUpdate(n_steps); + + this->timesteps_taken += n_steps; + + for(int ic=0;icGetNumberOfChemicals();ic++) + this->images[ic]->Modified(); + + if(this->rearrange_fields_filter && this->assign_attribute_filter) + { + // manually update the rendering pipeline to allow for changing array names + // TODO: this step shouldn't be necessary + this->rearrange_fields_filter->Update(); + assign_attribute_filter->Assign(this->rearrange_fields_filter->GetOutput()->GetCellData()->GetArray(0)->GetName(), + vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::InitializeRenderPipeline(vtkRenderer* pRenderer,const Properties& render_settings) +{ + this->rearrange_fields_filter = NULL; + this->assign_attribute_filter = NULL; + + switch(this->GetArenaDimensionality()) + { + // TODO: merge the dimensionalities (often want one/more slices from lower dimensionalities) + case 0: + case 1: this->InitializeVTKPipeline_1D(pRenderer,render_settings); break; + case 2: this->InitializeVTKPipeline_2D(pRenderer,render_settings); break; + case 3: this->InitializeVTKPipeline_3D(pRenderer,render_settings); break; + default: + throw runtime_error("ImageRD::InitializeRenderPipeline : Unsupported dimensionality"); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::InitializeVTKPipeline_1D(vtkRenderer* pRenderer,const Properties& render_settings) +{ + float low = render_settings.GetProperty("low").GetFloat(); + float high = render_settings.GetProperty("high").GetFloat(); + float vertical_scale_1D = render_settings.GetProperty("vertical_scale_1D").GetFloat(); + bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); + int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); + bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); + bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); + bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); + int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); + int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); + int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); + bool plot_ab_orthogonally = render_settings.GetProperty("plot_ab_orthogonally").GetBool(); + if (plot_ab_orthogonally && this->GetNumberOfChemicals() <= 1) + { + plot_ab_orthogonally = false; + } + + int iFirstChem = 0; + int iLastChem = this->GetNumberOfChemicals() - 1; + if(!show_multiple_chemicals) + { + if (plot_ab_orthogonally && iActiveChemical < 2) + { + iFirstChem = 0; + iLastChem = 1; + } + else + { + iFirstChem = iActiveChemical; + iLastChem = iFirstChem; + } + } + + float scaling = vertical_scale_1D / (high-low); // vertical_scale gives the height of the graph in worldspace units + const float image_height = this->GetX() / this->image_ratio1D; // we thicken it + const float y_gap = image_height; + + vtkSmartPointer lut = GetColorMap(render_settings); + + for(int iChem = iFirstChem; iChem <= iLastChem; ++iChem) + { + // pass the image through the lookup table + vtkSmartPointer image_mapper = vtkSmartPointer::New(); + image_mapper->SetLookupTable(lut); + image_mapper->SetInputData(this->GetImage(iChem)); + + // will convert the x*y 2D image to a x*y grid of quads + const float image_offset = this->image_top1D - image_height * 2.0f * (iChem - iFirstChem); + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetXResolution(this->GetX()); + plane->SetYResolution(this->GetY()); + plane->SetOrigin(0,image_offset-image_height,0); + plane->SetPoint1(this->GetX(),image_offset-image_height,0); + plane->SetPoint2(0,image_offset,0); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_mapper->GetOutputPort()); + if(use_image_interpolation) + texture->InterpolateOn(); + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(plane->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetTexture(texture); + if(show_cell_edges) + actor->GetProperty()->EdgeVisibilityOn(); + actor->GetProperty()->SetEdgeColor(0,0,0); + actor->GetProperty()->LightingOff(); + pRenderer->AddActor(actor); + + // add a text label + if(show_chemical_label && this->GetNumberOfChemicals()>1) + { + vtkSmartPointer captionActor = vtkSmartPointer::New(); + captionActor->SetAttachmentPoint(-image_height, image_offset - image_height/2, 0); + captionActor->SetPosition(0, 0); + captionActor->SetCaption(GetChemicalName(iChem).c_str()); + captionActor->BorderOff(); + captionActor->LeaderOff(); + captionActor->SetPadding(0); + captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); + captionActor->GetCaptionTextProperty()->BoldOff(); + captionActor->GetCaptionTextProperty()->ShadowOff(); + captionActor->GetCaptionTextProperty()->ItalicOff(); + captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); + captionActor->GetCaptionTextProperty()->SetFontSize(16); + captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); + captionActor->GetTextActor()->SetTextScaleModeToNone(); + pRenderer->AddActor(captionActor); + } + } + + // also add a scalar bar to show how the colors correspond to values + if(show_color_scale) + { + AddScalarBar(pRenderer,lut); + } + + // add a line graph for all the chemicals (active one highlighted) + const float graph_bottom = this->image_top1D + y_gap; + const float graph_top = graph_bottom + (high-low) * scaling; + for(int iChemical = iFirstChem; iChemical <= iLastChem; iChemical++) + { + if (plot_ab_orthogonally && iChemical == 1) + { + continue; + } + vtkSmartPointer mapper = vtkSmartPointer::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); + if (plot_ab_orthogonally && iChemical == 0) + { + // plot the merged ab pair here + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetInputData(this->GetImage(0)); + vtkSmartPointer warp_y = vtkSmartPointer::New(); + warp_y->SetInputConnection(plane->GetOutputPort()); + warp_y->SetScaleFactor(scaling); + warp_y->SetNormal(0, 1, 0); + vtkSmartPointer plane2 = vtkSmartPointer::New(); + plane2->SetInputData(this->GetImage(1)); + vtkSmartPointer merge = vtkSmartPointer::New(); + merge->SetGeometryConnection(warp_y->GetOutputPort()); + merge->SetScalarsConnection(plane2->GetOutputPort()); + vtkSmartPointer warp_z = vtkSmartPointer::New(); + warp_z->SetInputConnection(merge->GetOutputPort()); + warp_z->SetScaleFactor(scaling); + warp_z->SetNormal(0, 0, -1); + vtkSmartPointer stripper = vtkSmartPointer::New(); + stripper->SetInputConnection(warp_z->GetOutputPort()); + vtkSmartPointer tube = vtkSmartPointer::New(); + tube->SetInputConnection(stripper->GetOutputPort()); + tube->SetRadius(this->GetX() / 512.0); + tube->SetNumberOfSides(6); + mapper->SetInputConnection(tube->GetOutputPort()); + actor->GetProperty()->SetColor(1, 1, 1); + actor->GetProperty()->SetAmbient(0.3); + } + else + { + // plot this chemical in the normal way + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetInputData(this->GetImage(iChemical)); + vtkSmartPointer warp = vtkSmartPointer::New(); + warp->SetInputConnection(plane->GetOutputPort()); + warp->SetScaleFactor(scaling); + warp->SetNormal(0, 1, 0); + mapper->SetInputConnection(warp->GetOutputPort()); + actor->GetProperty()->SetAmbient(1); + if (iChemical == iActiveChemical) + actor->GetProperty()->SetColor(1, 1, 1); + else + actor->GetProperty()->SetColor(0.5, 0.5, 0.5); + } + mapper->ScalarVisibilityOff(); + actor->SetMapper(mapper); + actor->PickableOff(); + actor->SetPosition(0, graph_bottom - low * scaling,0); + pRenderer->AddActor(actor); + } + + // add an axis + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(0,0,graph_bottom,graph_top,0,0); + axis->SetRanges(0,0,low,high,0,0); + axis->UseRangesOn(); + axis->XAxisVisibilityOff(); + axis->ZAxisVisibilityOff(); + axis->SetYLabel(""); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + if (plot_ab_orthogonally) + { + axis->SetYLabel("a"); + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(0, 0, graph_top, graph_top, -low * scaling, -high * scaling); + axis->SetRanges(0, 0, 0, 0, low, high); + axis->UseRangesOn(); + axis->XAxisVisibilityOff(); + axis->YAxisVisibilityOff(); + axis->SetZLabel("b"); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + } + + // add a phase plot + const float phase_plot_bottom = graph_top + y_gap*2; + if(show_phase_plot && this->GetNumberOfChemicals()>=2) + { + this->AddPhasePlot(pRenderer,scaling,low,high,0.0f, phase_plot_bottom,0.0f,iPhasePlotX,iPhasePlotY,iPhasePlotZ); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::InitializeVTKPipeline_2D(vtkRenderer* pRenderer,const Properties& render_settings) +{ + float low = render_settings.GetProperty("low").GetFloat(); + float high = render_settings.GetProperty("high").GetFloat(); + float vertical_scale_2D = render_settings.GetProperty("vertical_scale_2D").GetFloat(); + bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); + int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + bool use_wireframe = render_settings.GetProperty("use_wireframe").GetBool(); + float surface_r,surface_g,surface_b; + render_settings.GetProperty("surface_color").GetColor(surface_r,surface_g,surface_b); + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + bool show_displacement_mapped_surface = render_settings.GetProperty("show_displacement_mapped_surface").GetBool(); + bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); + bool color_displacement_mapped_surface = render_settings.GetProperty("color_displacement_mapped_surface").GetBool(); + bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); + bool show_bounding_box = render_settings.GetProperty("show_bounding_box").GetBool(); + bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); + bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); + int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); + int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); + int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); + + const float scaling = vertical_scale_2D / (high-low); // vertical_scale gives the height of the graph in worldspace units + const float x_gap = this->x_spacing_proportion * this->GetX(); + const float y_gap = this->y_spacing_proportion * this->GetY(); + + double offset[3] = {0,0,0}; + const float surface_bottom = offset[1] + 0.5 + this->GetY() + y_gap; + const float surface_top = surface_bottom + this->GetY(); + + int iFirstChem = 0; + int iLastChem = this->GetNumberOfChemicals() - 1; + if(!show_multiple_chemicals) { iFirstChem = iActiveChemical; iLastChem = iFirstChem; } + + vtkSmartPointer lut = GetColorMap(render_settings); + + for(int iChem = iFirstChem; iChem <= iLastChem; iChem++) + { + // pass the image through the lookup table + vtkSmartPointer image_mapper = vtkSmartPointer::New(); + image_mapper->SetLookupTable(lut); + image_mapper->SetInputData(this->GetImage(iChem)); + + // will convert the x*y 2D image to a x*y grid of quads + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetXResolution(this->GetX()); + plane->SetYResolution(this->GetY()); + plane->SetOrigin(0,0,0); + plane->SetPoint1(this->GetX(),0,0); + plane->SetPoint2(0,this->GetY(),0); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_mapper->GetOutputPort()); + if(use_image_interpolation) + texture->InterpolateOn(); + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(plane->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetPosition(offset); + actor->SetTexture(texture); + if(show_cell_edges) + actor->GetProperty()->EdgeVisibilityOn(); + actor->GetProperty()->SetEdgeColor(0,0,0); + actor->GetProperty()->LightingOff(); + pRenderer->AddActor(actor); + + if(show_displacement_mapped_surface) + { + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetInputData(this->GetImage(iChem)); + vtkSmartPointer warp = vtkSmartPointer::New(); + warp->SetInputConnection(plane->GetOutputPort()); + warp->SetScaleFactor(scaling); + vtkSmartPointer normals = vtkSmartPointer::New(); + normals->SetInputConnection(warp->GetOutputPort()); + normals->SplittingOff(); + vtkSmartPointer mapper = vtkSmartPointer::New(); + if(color_displacement_mapped_surface) + { + vtkSmartPointer tmap = vtkSmartPointer::New(); + tmap->SetOrigin(0,0,0); + tmap->SetPoint1(this->GetX(),0,0); + tmap->SetPoint2(0,this->GetY(),0); + tmap->SetInputConnection(normals->GetOutputPort()); + mapper->SetInputConnection(tmap->GetOutputPort()); + } + else + mapper->SetInputConnection(normals->GetOutputPort()); + mapper->ScalarVisibilityOff(); + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(surface_r,surface_g,surface_b); + actor->GetProperty()->SetAmbient(0.1); + actor->GetProperty()->SetDiffuse(0.7); + actor->GetProperty()->SetSpecular(0.2); + actor->GetProperty()->SetSpecularPower(3); + if(use_wireframe) + actor->GetProperty()->SetRepresentationToWireframe(); + actor->SetPosition(offset[0]+0.5, surface_bottom, offset[2] - low*scaling); + actor->PickableOff(); + pRenderer->AddActor(actor); + + // add the color image as the texture of the displacement-mapped surface + if(color_displacement_mapped_surface) + { + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_mapper->GetOutputPort()); + if(use_image_interpolation) + texture->InterpolateOn(); + else + texture->InterpolateOn(); + actor->SetTexture(texture); + } + + // add the bounding box + if(show_bounding_box) + { + vtkSmartPointer box = vtkSmartPointer::New(); + box->SetBounds(0,this->GetX()-1,0,this->GetY()-1,0,(high-low)*scaling); + + vtkSmartPointer edges = vtkSmartPointer::New(); + edges->SetInputConnection(box->GetOutputPort()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(edges->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(0,0,0); + actor->GetProperty()->SetAmbient(1); + actor->SetPosition(offset[0]+0.5,surface_bottom,offset[2]); + actor->PickableOff(); + + pRenderer->AddActor(actor); + } + } + + // add a text label + if(show_chemical_label && this->GetNumberOfChemicals()>1) + { + const float text_label_offset = 5.0 + max(this->GetX(), this->GetY()) / 20.0f; + vtkSmartPointer captionActor = vtkSmartPointer::New(); + captionActor->SetAttachmentPoint(offset[0] + this->GetX() / 2, offset[1] - text_label_offset, offset[2]); + captionActor->SetPosition(0, 0); + captionActor->SetCaption(GetChemicalName(iChem).c_str()); + captionActor->BorderOff(); + captionActor->LeaderOff(); + captionActor->SetPadding(0); + captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); + captionActor->GetCaptionTextProperty()->BoldOff(); + captionActor->GetCaptionTextProperty()->ShadowOff(); + captionActor->GetCaptionTextProperty()->ItalicOff(); + captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); + captionActor->GetCaptionTextProperty()->SetFontSize(16); + captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); + captionActor->GetTextActor()->SetTextScaleModeToNone(); + pRenderer->AddActor(captionActor); + } + + offset[0] += this->GetX() + x_gap; // the next chemical should appear further to the right + } + + // add an axis to the first diplacement-mapped surface + if(show_displacement_mapped_surface) + { + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(0.5,0.5,surface_top,surface_top,0,(high-low)*scaling); + axis->SetRanges(0,0,0,0,low,high); + axis->UseRangesOn(); + axis->XAxisVisibilityOff(); + axis->YAxisVisibilityOff(); + axis->SetZLabel(""); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + } + + // add a scalar bar to show how the colors correspond to values + if(show_color_scale) + { + AddScalarBar(pRenderer,lut); + } + + // add a phase plot + if(show_phase_plot && this->GetNumberOfChemicals()>=2) + { + float phase_plot_bottom = surface_bottom; + if(show_displacement_mapped_surface) + phase_plot_bottom = surface_top + y_gap * 2; + + this->AddPhasePlot(pRenderer,this->GetX()/(high-low),low,high,0.0f, phase_plot_bottom,0.0f,iPhasePlotX,iPhasePlotY,iPhasePlotZ); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::InitializeVTKPipeline_3D(vtkRenderer* pRenderer,const Properties& render_settings) +{ + float low = render_settings.GetProperty("low").GetFloat(); + float high = render_settings.GetProperty("high").GetFloat(); + bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + float contour_level = render_settings.GetProperty("contour_level").GetFloat(); + bool cap_contour = render_settings.GetProperty("cap_contour").GetBool(); + bool invert_contour_cap = render_settings.GetProperty("invert_contour_cap").GetBool(); + bool use_wireframe = render_settings.GetProperty("use_wireframe").GetBool(); + bool slice_3D = render_settings.GetProperty("slice_3D").GetBool(); + string slice_3D_axis = render_settings.GetProperty("slice_3D_axis").GetAxis(); + float slice_3D_position = render_settings.GetProperty("slice_3D_position").GetFloat(); + float surface_r,surface_g,surface_b; + render_settings.GetProperty("surface_color").GetColor(surface_r,surface_g,surface_b); + bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); + bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); + bool show_bounding_box = render_settings.GetProperty("show_bounding_box").GetBool(); + bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); + bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); + int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); + int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); + int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); + + vtkSmartPointer lut = GetColorMap(render_settings); + + int iFirstChem = 0; + int iLastChem = this->GetNumberOfChemicals() - 1; + if(!show_multiple_chemicals) { iFirstChem = iActiveChemical; iLastChem = iFirstChem; } + + const float x_gap = this->x_spacing_proportion * this->GetX(); + const float y_gap = this->y_spacing_proportion * this->GetY(); + double offset[3] = {0,0,0}; + + for(int iChem = iFirstChem; iChem <= iLastChem; ++iChem) + { + vtkSmartPointer mapper = vtkSmartPointer::New(); + + vtkImageData *image = this->GetImage(iChem); + int *extent = image->GetExtent(); + + // we first convert the image from point data to cell data, to match the users expectations + + vtkSmartPointer pad = vtkSmartPointer::New(); + pad->SetInputData(image); + pad->SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); + + // move the pixel values (stored in the point data) to cell data + vtkSmartPointer prearrange_fields = vtkSmartPointer::New(); + prearrange_fields->SetInputData(image); + prearrange_fields->AddOperation(vtkRearrangeFields::MOVE,vtkDataSetAttributes::SCALARS, + vtkRearrangeFields::POINT_DATA,vtkRearrangeFields::CELL_DATA); + + // get the image scalars name from the first array + prearrange_fields->Update(); + const char *scalars_array_name = prearrange_fields->GetOutput()->GetCellData()->GetArray(0)->GetName(); + + // mark the new cell data array as the active attribute + vtkSmartPointer assign_attribute = vtkSmartPointer::New(); + assign_attribute->SetInputConnection(prearrange_fields->GetOutputPort()); + assign_attribute->Assign(scalars_array_name, vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); + + // save the filters so we can perform a manual update step on the pipeline in Update() (TODO: work out how to do this properly) + this->rearrange_fields_filter = prearrange_fields; + this->assign_attribute_filter = assign_attribute; + + vtkSmartPointer merge_datasets = vtkSmartPointer::New(); + merge_datasets->SetGeometryConnection(pad->GetOutputPort()); + merge_datasets->SetScalarsConnection(assign_attribute->GetOutputPort()); + + vtkSmartPointer to_point_data = vtkSmartPointer::New(); // (only used if needed) + to_point_data->SetInputConnection(merge_datasets->GetOutputPort()); + + if(use_image_interpolation) + { + // turns the 3d grid of sampled values into a polygon mesh for rendering, + // by making a surface that contours the volume at a specified level + vtkSmartPointer surface = vtkSmartPointer::New(); + surface->SetInputConnection(to_point_data->GetOutputPort()); + surface->SetValue(0, contour_level); + + vtkSmartPointer append = vtkSmartPointer::New(); + append->AddInputConnection(surface->GetOutputPort()); + + if (cap_contour) + { + // pad outside the volume with zero so that the contour caps the ends instead of leaving holes + vtkSmartPointer cap_pad = vtkSmartPointer::New(); + cap_pad->SetInputConnection(to_point_data->GetOutputPort()); + cap_pad->SetOutputWholeExtent(extent[0] - 1, extent[1] + 2, extent[2] - 1, extent[3] + 2, extent[4] - 1, extent[5] + 2); + if (invert_contour_cap) + { + cap_pad->SetConstant(high + (high - low)); + } + else + { + cap_pad->SetConstant(low + (low - high)); + } + + // again make the same contour surface + vtkSmartPointer cap_surface = vtkSmartPointer::New(); + cap_surface->SetInputConnection(cap_pad->GetOutputPort()); + cap_surface->SetValue(0, contour_level); + + // clip away the internal parts of the volume, to leave only the caps + vtkSmartPointer box = vtkSmartPointer::New(); + double* bounds = image->GetBounds(); + box->SetBounds(bounds[0], bounds[1] + 1, bounds[2], bounds[3] + 1, bounds[4], bounds[5] + 1); + vtkSmartPointer gf = vtkSmartPointer::New(); + gf->SetInputConnection(cap_surface->GetOutputPort()); + gf->SetImplicitFunction(box); + gf->SetExtractInside(0); + + // throw away the normals from the volume, to leave flat sharp normals on the caps + vtkSmartPointer normals = vtkSmartPointer::New(); + normals->SetInputConnection(gf->GetOutputPort()); + normals->SetFeatureAngle(5); + + // add the caps to the scene with their own normals + append->AddInputConnection(normals->GetOutputPort()); + } + + mapper->SetInputConnection(append->GetOutputPort()); + mapper->ScalarVisibilityOff(); + } + else + { + // render as cubes, Minecraft-style + vtkSmartPointer threshold = vtkSmartPointer::New(); + threshold->SetInputConnection(merge_datasets->GetOutputPort()); + threshold->SetInputArrayToProcess(0, 0, 0, + vtkDataObject::FIELD_ASSOCIATION_CELLS, + vtkDataSetAttributes::SCALARS); +#if VTK_MAJOR_VERSION > 9 || (VTK_MAJOR_VERSION == 9 && VTK_MINOR_VERSION >= 1) + threshold->SetUpperThreshold(contour_level); + threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER); +#else + threshold->ThresholdByUpper(contour_level); +#endif + + vtkSmartPointer geometry = vtkSmartPointer::New(); + geometry->SetInputConnection(threshold->GetOutputPort()); + + mapper->SetInputConnection(geometry->GetOutputPort()); + } + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(surface_r,surface_g,surface_b); + actor->GetProperty()->SetAmbient(0.1); + actor->GetProperty()->SetDiffuse(0.5); + actor->GetProperty()->SetSpecular(0.4); + actor->GetProperty()->SetSpecularPower(10); + if(use_wireframe) + actor->GetProperty()->SetRepresentationToWireframe(); + if(show_cell_edges && !use_image_interpolation) + { + actor->GetProperty()->EdgeVisibilityOn(); + actor->GetProperty()->SetEdgeColor(0,0,0); + } + vtkSmartPointer bfprop = vtkSmartPointer::New(); + actor->SetBackfaceProperty(bfprop); + bfprop->SetColor(0.7,0.6,0.55); + bfprop->SetAmbient(0.1); + bfprop->SetDiffuse(0.5); + bfprop->SetSpecular(0.4); + bfprop->SetSpecularPower(10); + actor->SetPosition(offset); + + // add the actor to the renderer's scene + actor->PickableOff(); // not sure about this - sometimes it is nice to paint on the contoured surface too, for 3d sculpting + pRenderer->AddActor(actor); + + // add the bounding box + if(show_bounding_box) + { + vtkSmartPointer box = vtkSmartPointer::New(); + box->SetBounds(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); + + vtkSmartPointer edges = vtkSmartPointer::New(); + edges->SetInputConnection(box->GetOutputPort()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(edges->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(0,0,0); + actor->GetProperty()->SetAmbient(1); + actor->SetPosition(offset); + actor->PickableOff(); + + pRenderer->AddActor(actor); + } + + // add a 2D slice too + if(slice_3D) + { + vtkSmartPointer plane = vtkSmartPointer::New(); + double *bounds = image->GetBounds(); + plane->SetOrigin(slice_3D_position*(bounds[1]-bounds[0])+bounds[0], + slice_3D_position*(bounds[3]-bounds[2])+bounds[2], + slice_3D_position*(bounds[5]-bounds[4])+bounds[4]); + if(slice_3D_axis=="x") + plane->SetNormal(1,0,0); + else if(slice_3D_axis=="y") + plane->SetNormal(0,1,0); + else + plane->SetNormal(0,0,1); + vtkSmartPointer cutter = vtkSmartPointer::New(); + cutter->SetCutFunction(plane); + if(use_image_interpolation) + cutter->SetInputConnection(to_point_data->GetOutputPort()); + else + cutter->SetInputConnection(merge_datasets->GetOutputPort()); + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(cutter->GetOutputPort()); + mapper->SetLookupTable(lut); + mapper->UseLookupTableScalarRangeOn(); + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->LightingOff(); + if(show_cell_edges) + { + actor->GetProperty()->EdgeVisibilityOn(); + actor->GetProperty()->SetEdgeColor(0,0,0); // could be a user option + } + actor->SetPosition(offset); + pRenderer->AddActor(actor); + } + + // add a text label + if(show_chemical_label && this->GetNumberOfChemicals()>1) + { + const float text_label_offset = 5.0 + max(this->GetX(), this->GetY()) / 20.0f; + vtkSmartPointer captionActor = vtkSmartPointer::New(); + captionActor->SetAttachmentPoint(offset[0] + this->GetX() / 2, offset[1] - text_label_offset, offset[2]); + captionActor->SetPosition(0, 0); + captionActor->SetCaption(GetChemicalName(iChem).c_str()); + captionActor->BorderOff(); + captionActor->LeaderOff(); + captionActor->SetPadding(0); + captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); + captionActor->GetCaptionTextProperty()->BoldOff(); + captionActor->GetCaptionTextProperty()->ShadowOff(); + captionActor->GetCaptionTextProperty()->ItalicOff(); + captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); + captionActor->GetCaptionTextProperty()->SetFontSize(16); + captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); + captionActor->GetTextActor()->SetTextScaleModeToNone(); + pRenderer->AddActor(captionActor); + } + + offset[0] += this->GetX() + x_gap; // the next chemical should appear further to the right + } + + // also add a scalar bar to show how the colors correspond to values + if (show_color_scale) + { + AddScalarBar(pRenderer, lut); + } + + // add a phase plot + if(show_phase_plot && this->GetNumberOfChemicals()>=2) + { + this->AddPhasePlot( pRenderer,this->GetX()/(high-low),low,high,0.0f,this->GetY()+y_gap,0.0f, + iPhasePlotX,iPhasePlotY,iPhasePlotZ); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::AddPhasePlot(vtkRenderer* pRenderer,float scaling,float low,float high,float posX,float posY,float posZ, + int iChemX,int iChemY,int iChemZ) +{ + iChemX = max( 0, min( iChemX, this->GetNumberOfChemicals()-1 ) ); + iChemY = max( 0, min( iChemY, this->GetNumberOfChemicals()-1 ) ); + iChemZ = max( 0, min( iChemZ, this->GetNumberOfChemicals()-1 ) ); + + // ensure plot points remain within a reasonable range (else get view clipping issues) + double minVal = low-(high-low)*100.0; + double maxVal = high+(high-low)*100.0; + + vtkSmartPointer points = vtkSmartPointer::New(); + points->SetNumberOfPoints(this->GetNumberOfCells()); + points->SetRadius(0); + + vtkSmartPointer thresholdXmin = vtkSmartPointer::New(); + thresholdXmin->SetInputData(this->GetImage(iChemX)); + thresholdXmin->ThresholdByLower(minVal); + thresholdXmin->ReplaceInOn(); + thresholdXmin->SetInValue(minVal); + thresholdXmin->ReplaceOutOff(); + vtkSmartPointer thresholdXmax = vtkSmartPointer::New(); + thresholdXmax->SetInputConnection(thresholdXmin->GetOutputPort()); + thresholdXmax->ThresholdByUpper(maxVal); + thresholdXmax->ReplaceInOn(); + thresholdXmax->SetInValue(maxVal); + thresholdXmax->ReplaceOutOff(); + + vtkSmartPointer mergeX = vtkSmartPointer::New(); + mergeX->SetGeometryConnection(points->GetOutputPort()); + mergeX->SetScalarsConnection(thresholdXmax->GetOutputPort()); + + vtkSmartPointer warpX = vtkSmartPointer::New(); + warpX->UseNormalOn(); + warpX->SetNormal(1,0,0); + warpX->SetInputConnection(mergeX->GetOutputPort()); + warpX->SetScaleFactor(scaling); + + vtkSmartPointer thresholdYmin = vtkSmartPointer::New(); + thresholdYmin->SetInputData(this->GetImage(iChemY)); + thresholdYmin->ThresholdByLower(minVal); + thresholdYmin->ReplaceInOn(); + thresholdYmin->SetInValue(minVal); + thresholdYmin->ReplaceOutOff(); + vtkSmartPointer thresholdYmax = vtkSmartPointer::New(); + thresholdYmax->SetInputConnection(thresholdYmin->GetOutputPort()); + thresholdYmax->ThresholdByUpper(maxVal); + thresholdYmax->ReplaceInOn(); + thresholdYmax->SetInValue(maxVal); + thresholdYmax->ReplaceOutOff(); + + vtkSmartPointer mergeY = vtkSmartPointer::New(); + mergeY->SetGeometryConnection(warpX->GetOutputPort()); + mergeY->SetScalarsConnection(thresholdYmax->GetOutputPort()); + + vtkSmartPointer warpY = vtkSmartPointer::New(); + warpY->UseNormalOn(); + warpY->SetNormal(0,1,0); + warpY->SetInputConnection(mergeY->GetOutputPort()); + warpY->SetScaleFactor(scaling); + + vtkSmartPointer glyph = vtkSmartPointer::New(); + + float offsetZ = 0.0f; + if(this->GetNumberOfChemicals()>2) + { + vtkSmartPointer thresholdZmin = vtkSmartPointer::New(); + thresholdZmin->SetInputData(this->GetImage(iChemZ)); + thresholdZmin->ThresholdByLower(minVal); + thresholdZmin->ReplaceInOn(); + thresholdZmin->SetInValue(minVal); + thresholdZmin->ReplaceOutOff(); + vtkSmartPointer thresholdZmax = vtkSmartPointer::New(); + thresholdZmax->SetInputConnection(thresholdZmin->GetOutputPort()); + thresholdZmax->ThresholdByUpper(maxVal); + thresholdZmax->ReplaceInOn(); + thresholdZmax->SetInValue(maxVal); + thresholdZmax->ReplaceOutOff(); + + vtkSmartPointer mergeZ = vtkSmartPointer::New(); + mergeZ->SetGeometryConnection(warpY->GetOutputPort()); + mergeZ->SetScalarsConnection(thresholdZmax->GetOutputPort()); + + vtkSmartPointer warpZ = vtkSmartPointer::New(); + warpZ->UseNormalOn(); + warpZ->SetNormal(0,0,1); + warpZ->SetInputConnection(mergeZ->GetOutputPort()); + warpZ->SetScaleFactor(scaling); + + glyph->SetInputConnection(warpZ->GetOutputPort()); + + offsetZ = low*scaling; + } + else + { + glyph->SetInputConnection(warpY->GetOutputPort()); + } + + vtkSmartPointer trans = vtkSmartPointer::New(); + trans->Scale(1,1,-1); + vtkSmartPointer transFilter = vtkSmartPointer::New(); + transFilter->SetTransform(trans); + transFilter->SetInputConnection(glyph->GetOutputPort()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(transFilter->GetOutputPort()); + mapper->ScalarVisibilityOff(); + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetAmbient(1); + actor->GetProperty()->SetPointSize(1); + actor->PickableOff(); + actor->SetPosition(posX-low*scaling,posY-low*scaling,posZ+offsetZ); + pRenderer->AddActor(actor); + + // also add the axes + { + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(posX,posX+scaling*(high-low),posY,posY,posZ,posZ); + axis->SetRanges(low,high,0,0,0,0); + axis->UseRangesOn(); + axis->YAxisVisibilityOff(); + axis->ZAxisVisibilityOff(); + axis->SetXLabel(GetChemicalName(iChemX).c_str()); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + } + { + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(posX,posX,posY,posY+(high-low)*scaling,posZ,posZ); + axis->SetRanges(0,0,low,high,0,0); + axis->UseRangesOn(); + axis->XAxisVisibilityOff(); + axis->ZAxisVisibilityOff(); + axis->SetYLabel(GetChemicalName(iChemY).c_str()); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + } + if(this->GetNumberOfChemicals()>2) + { + vtkSmartPointer axis = vtkSmartPointer::New(); + axis->SetCamera(pRenderer->GetActiveCamera()); + axis->SetBounds(posX,posX,posY,posY,posZ,posZ-scaling*(high-low)); + axis->SetRanges(0,0,0,0,low,high); + axis->UseRangesOn(); + axis->XAxisVisibilityOff(); + axis->YAxisVisibilityOff(); + axis->SetZLabel(GetChemicalName(iChemZ).c_str()); + axis->SetLabelFormat("%.2f"); + axis->SetInertia(10000); + axis->SetCornerOffset(0); + axis->SetNumberOfLabels(5); + axis->PickableOff(); + pRenderer->AddActor(axis); + } +} + +// --------------------------------------------------------------------- + +void ImageRD::SaveStartingPattern() +{ + this->GetImage(this->starting_pattern); +} + +// --------------------------------------------------------------------- + +void ImageRD::RestoreStartingPattern() +{ + this->CopyFromImage(this->starting_pattern); + this->timesteps_taken = 0; +} + +// --------------------------------------------------------------------- + +void ImageRD::SetDimensions(int x, int y, int z) +{ + this->AllocateImages(x,y,z,this->GetNumberOfChemicals(),this->data_type); +} + +// --------------------------------------------------------------------- + +void ImageRD::SetNumberOfChemicals(int n, bool reallocate_storage) +{ + const int X = this->GetX(); + const int Y = this->GetY(); + const int Z = this->GetZ(); + if (reallocate_storage) + { + this->DeallocateImages(); + } + if (n == this->n_chemicals) { + return; + } + if (n > this->n_chemicals) + { + while (static_cast(this->images.size()) < n) { + this->images.push_back( AllocateVTKImage(X, Y, Z, this->data_type) ); + this->images.back()->GetPointData()->GetScalars()->FillComponent(0, 0.0); + } + } + else { + this->images.resize(n); + } + this->n_chemicals = n; + this->is_modified = true; +} + +// --------------------------------------------------------------------- + +void ImageRD::SetDimensionsAndNumberOfChemicals(int x,int y,int z,int nc) +{ + this->AllocateImages(x,y,z,nc,this->data_type); +} + +// --------------------------------------------------------------------- + +int ImageRD::GetNumberOfCells() const +{ + return this->GetX() * this->GetY() * this->GetZ(); +} + +// --------------------------------------------------------------------- + +void ImageRD::GetAsMesh(vtkPolyData *out, const Properties &render_settings) const +{ + bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); + int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + float contour_level = render_settings.GetProperty("contour_level").GetFloat(); + + float low = render_settings.GetProperty("low").GetFloat(); + float high = render_settings.GetProperty("high").GetFloat(); + float vertical_scale_1D = render_settings.GetProperty("vertical_scale_1D").GetFloat(); + float vertical_scale_2D = render_settings.GetProperty("vertical_scale_2D").GetFloat(); + + switch(this->GetArenaDimensionality()) + { + case 1: + { + float scaling = vertical_scale_1D / (high-low); // vertical_scale gives the height of the graph in worldspace units + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetInputData(this->GetImage(iActiveChemical)); + vtkSmartPointer warp = vtkSmartPointer::New(); + warp->SetInputConnection(plane->GetOutputPort()); + warp->SetScaleFactor(-scaling); + warp->Update(); + out->DeepCopy(warp->GetOutput()); + } + break; + case 2: + { + float scaling = vertical_scale_2D / (high-low); // vertical_scale gives the height of the graph in worldspace units + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetInputData(this->GetImage(iActiveChemical)); + vtkSmartPointer warp = vtkSmartPointer::New(); + warp->SetInputConnection(plane->GetOutputPort()); + warp->SetScaleFactor(scaling); + vtkSmartPointer normals = vtkSmartPointer::New(); + normals->SetInputConnection(warp->GetOutputPort()); + normals->SplittingOff(); + normals->Update(); + out->DeepCopy(normals->GetOutput()); + } + break; + case 3: + if(use_image_interpolation) + { + // turns the 3d grid of sampled values into a polygon mesh for rendering, + // by making a surface that contours the volume at a specified level + vtkSmartPointer surface = vtkSmartPointer::New(); + surface->SetInputData(this->GetImage(iActiveChemical)); + surface->SetValue(0, contour_level); + surface->Update(); + out->DeepCopy(surface->GetOutput()); + } + else + { + // render as cubes, Minecraft-style + vtkImageData *image = this->GetImage(iActiveChemical); + int *extent = image->GetExtent(); + + vtkSmartPointer pad = vtkSmartPointer::New(); + pad->SetInputData(image); + pad->SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); + pad->Update(); + pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars()); // a non-pipelined operation + + vtkSmartPointer threshold = vtkSmartPointer::New(); + threshold->SetInputConnection(pad->GetOutputPort()); + threshold->SetInputArrayToProcess(0, 0, 0, + vtkDataObject::FIELD_ASSOCIATION_CELLS, + vtkDataSetAttributes::SCALARS); +#if VTK_MAJOR_VERSION > 9 || (VTK_MAJOR_VERSION == 9 && VTK_MINOR_VERSION >= 1) + threshold->SetUpperThreshold(contour_level); + threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER); +#else + threshold->ThresholdByUpper(contour_level); +#endif + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Translate (-.5, -.5, -.5); + vtkSmartPointer transformModel = vtkSmartPointer::New(); + transformModel->SetTransform(transform); + transformModel->SetInputConnection(threshold->GetOutputPort()); + + vtkSmartPointer geometry = vtkSmartPointer::New(); + geometry->SetInputConnection(transformModel->GetOutputPort()); + geometry->Update(); + + out->DeepCopy(geometry->GetOutput()); + } + break; + } +} + +// --------------------------------------------------------------------- + +void ImageRD::SaveFile(const char* filename,const Properties& render_settings,bool generate_initial_pattern_when_loading) const +{ + // convert the image to named arrays + vtkSmartPointer im = vtkSmartPointer::New(); + im->DeepCopy(this->images.front()); + im->GetPointData()->SetScalars(NULL); + for(int iChem=0;iChemGetNumberOfChemicals();iChem++) + { + vtkSmartPointer da = vtkSmartPointer::Take( vtkDataArray::CreateDataArray( this->data_type ) ); + da->DeepCopy(this->images[iChem]->GetPointData()->GetScalars()); + da->SetName(GetChemicalName(iChem).c_str()); + im->GetPointData()->AddArray(da); + } + + vtkSmartPointer iw = vtkSmartPointer::New(); + iw->SetSystem(this); + iw->SetRenderSettings(&render_settings); + if(generate_initial_pattern_when_loading) + iw->GenerateInitialPatternWhenLoading(); + iw->SetFileName(filename); + iw->SetDataModeToBinary(); // (to match MeshRD::SaveFile()) + iw->SetInputData(im); + iw->Write(); +} + +// -------------------------------------------------------------------------------- + +void ImageRD::GetAs2DImage(vtkImageData *out,const Properties& render_settings) const +{ + int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + + // create a lookup table for mapping values to colors vtkSmartPointer lut = GetColorMap(render_settings); - for(int iChem = iFirstChem; iChem <= iLastChem; iChem++) - { - // pass the image through the lookup table - vtkSmartPointer image_mapper = vtkSmartPointer::New(); - image_mapper->SetLookupTable(lut); - image_mapper->SetInputData(this->GetImage(iChem)); - - // will convert the x*y 2D image to a x*y grid of quads - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetXResolution(this->GetX()); - plane->SetYResolution(this->GetY()); - plane->SetOrigin(0,0,0); - plane->SetPoint1(this->GetX(),0,0); - plane->SetPoint2(0,this->GetY(),0); - - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(image_mapper->GetOutputPort()); - if(use_image_interpolation) - texture->InterpolateOn(); - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(plane->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->SetPosition(offset); - actor->SetTexture(texture); - if(show_cell_edges) - actor->GetProperty()->EdgeVisibilityOn(); - actor->GetProperty()->SetEdgeColor(0,0,0); - actor->GetProperty()->LightingOff(); - pRenderer->AddActor(actor); - - if(show_displacement_mapped_surface) - { - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetInputData(this->GetImage(iChem)); - vtkSmartPointer warp = vtkSmartPointer::New(); - warp->SetInputConnection(plane->GetOutputPort()); - warp->SetScaleFactor(scaling); - vtkSmartPointer normals = vtkSmartPointer::New(); - normals->SetInputConnection(warp->GetOutputPort()); - normals->SplittingOff(); - vtkSmartPointer mapper = vtkSmartPointer::New(); - if(color_displacement_mapped_surface) - { - vtkSmartPointer tmap = vtkSmartPointer::New(); - tmap->SetOrigin(0,0,0); - tmap->SetPoint1(this->GetX(),0,0); - tmap->SetPoint2(0,this->GetY(),0); - tmap->SetInputConnection(normals->GetOutputPort()); - mapper->SetInputConnection(tmap->GetOutputPort()); - } - else - mapper->SetInputConnection(normals->GetOutputPort()); - mapper->ScalarVisibilityOff(); - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->SetColor(surface_r,surface_g,surface_b); - actor->GetProperty()->SetAmbient(0.1); - actor->GetProperty()->SetDiffuse(0.7); - actor->GetProperty()->SetSpecular(0.2); - actor->GetProperty()->SetSpecularPower(3); - if(use_wireframe) - actor->GetProperty()->SetRepresentationToWireframe(); - actor->SetPosition(offset[0]+0.5, surface_bottom, offset[2] - low*scaling); - actor->PickableOff(); - pRenderer->AddActor(actor); - - // add the color image as the texture of the displacement-mapped surface - if(color_displacement_mapped_surface) - { - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(image_mapper->GetOutputPort()); - if(use_image_interpolation) - texture->InterpolateOn(); - else - texture->InterpolateOn(); - actor->SetTexture(texture); - } - - // add the bounding box - if(show_bounding_box) - { - vtkSmartPointer box = vtkSmartPointer::New(); - box->SetBounds(0,this->GetX()-1,0,this->GetY()-1,0,(high-low)*scaling); - - vtkSmartPointer edges = vtkSmartPointer::New(); - edges->SetInputConnection(box->GetOutputPort()); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(edges->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->SetColor(0,0,0); - actor->GetProperty()->SetAmbient(1); - actor->SetPosition(offset[0]+0.5,surface_bottom,offset[2]); - actor->PickableOff(); - - pRenderer->AddActor(actor); - } - } - - // add a text label - if(show_chemical_label && this->GetNumberOfChemicals()>1) - { - const float text_label_offset = 5.0 + max(this->GetX(), this->GetY()) / 20.0f; - vtkSmartPointer captionActor = vtkSmartPointer::New(); - captionActor->SetAttachmentPoint(offset[0] + this->GetX() / 2, offset[1] - text_label_offset, offset[2]); - captionActor->SetPosition(0, 0); - captionActor->SetCaption(GetChemicalName(iChem).c_str()); - captionActor->BorderOff(); - captionActor->LeaderOff(); - captionActor->SetPadding(0); - captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); - captionActor->GetCaptionTextProperty()->BoldOff(); - captionActor->GetCaptionTextProperty()->ShadowOff(); - captionActor->GetCaptionTextProperty()->ItalicOff(); - captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); - captionActor->GetCaptionTextProperty()->SetFontSize(16); - captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); - captionActor->GetTextActor()->SetTextScaleModeToNone(); - pRenderer->AddActor(captionActor); - } - - offset[0] += this->GetX() + x_gap; // the next chemical should appear further to the right - } - - // add an axis to the first diplacement-mapped surface - if(show_displacement_mapped_surface) - { - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(0.5,0.5,surface_top,surface_top,0,(high-low)*scaling); - axis->SetRanges(0,0,0,0,low,high); - axis->UseRangesOn(); - axis->XAxisVisibilityOff(); - axis->YAxisVisibilityOff(); - axis->SetZLabel(""); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - } - - // add a scalar bar to show how the colors correspond to values - if(show_color_scale) - { - AddScalarBar(pRenderer,lut); - } - - // add a phase plot - if(show_phase_plot && this->GetNumberOfChemicals()>=2) - { - float phase_plot_bottom = surface_bottom; - if(show_displacement_mapped_surface) - phase_plot_bottom = surface_top + y_gap * 2; - - this->AddPhasePlot(pRenderer,this->GetX()/(high-low),low,high,0.0f, phase_plot_bottom,0.0f,iPhasePlotX,iPhasePlotY,iPhasePlotZ); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::InitializeVTKPipeline_3D(vtkRenderer* pRenderer,const Properties& render_settings) -{ - float low = render_settings.GetProperty("low").GetFloat(); - float high = render_settings.GetProperty("high").GetFloat(); - bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - float contour_level = render_settings.GetProperty("contour_level").GetFloat(); - bool cap_contour = render_settings.GetProperty("cap_contour").GetBool(); - bool invert_contour_cap = render_settings.GetProperty("invert_contour_cap").GetBool(); - bool use_wireframe = render_settings.GetProperty("use_wireframe").GetBool(); - bool slice_3D = render_settings.GetProperty("slice_3D").GetBool(); - string slice_3D_axis = render_settings.GetProperty("slice_3D_axis").GetAxis(); - float slice_3D_position = render_settings.GetProperty("slice_3D_position").GetFloat(); - float surface_r,surface_g,surface_b; - render_settings.GetProperty("surface_color").GetColor(surface_r,surface_g,surface_b); - bool show_color_scale = render_settings.GetProperty("show_color_scale").GetBool(); - bool show_cell_edges = render_settings.GetProperty("show_cell_edges").GetBool(); - bool show_bounding_box = render_settings.GetProperty("show_bounding_box").GetBool(); - bool show_chemical_label = render_settings.GetProperty("show_chemical_label").GetBool(); - bool show_phase_plot = render_settings.GetProperty("show_phase_plot").GetBool(); - int iPhasePlotX = IndexFromChemicalName(render_settings.GetProperty("phase_plot_x_axis").GetChemical()); - int iPhasePlotY = IndexFromChemicalName(render_settings.GetProperty("phase_plot_y_axis").GetChemical()); - int iPhasePlotZ = IndexFromChemicalName(render_settings.GetProperty("phase_plot_z_axis").GetChemical()); - - vtkSmartPointer lut = GetColorMap(render_settings); - - int iFirstChem = 0; - int iLastChem = this->GetNumberOfChemicals() - 1; - if(!show_multiple_chemicals) { iFirstChem = iActiveChemical; iLastChem = iFirstChem; } - - const float x_gap = this->x_spacing_proportion * this->GetX(); - const float y_gap = this->y_spacing_proportion * this->GetY(); - double offset[3] = {0,0,0}; - - for(int iChem = iFirstChem; iChem <= iLastChem; ++iChem) - { - vtkSmartPointer mapper = vtkSmartPointer::New(); - - vtkImageData *image = this->GetImage(iChem); - int *extent = image->GetExtent(); - - // we first convert the image from point data to cell data, to match the users expectations - - vtkSmartPointer pad = vtkSmartPointer::New(); - pad->SetInputData(image); - pad->SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); - - // move the pixel values (stored in the point data) to cell data - vtkSmartPointer prearrange_fields = vtkSmartPointer::New(); - prearrange_fields->SetInputData(image); - prearrange_fields->AddOperation(vtkRearrangeFields::MOVE,vtkDataSetAttributes::SCALARS, - vtkRearrangeFields::POINT_DATA,vtkRearrangeFields::CELL_DATA); - - // get the image scalars name from the first array - prearrange_fields->Update(); - const char *scalars_array_name = prearrange_fields->GetOutput()->GetCellData()->GetArray(0)->GetName(); - - // mark the new cell data array as the active attribute - vtkSmartPointer assign_attribute = vtkSmartPointer::New(); - assign_attribute->SetInputConnection(prearrange_fields->GetOutputPort()); - assign_attribute->Assign(scalars_array_name, vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); - - // save the filters so we can perform a manual update step on the pipeline in Update() (TODO: work out how to do this properly) - this->rearrange_fields_filter = prearrange_fields; - this->assign_attribute_filter = assign_attribute; - - vtkSmartPointer merge_datasets = vtkSmartPointer::New(); - merge_datasets->SetGeometryConnection(pad->GetOutputPort()); - merge_datasets->SetScalarsConnection(assign_attribute->GetOutputPort()); - - vtkSmartPointer to_point_data = vtkSmartPointer::New(); // (only used if needed) - to_point_data->SetInputConnection(merge_datasets->GetOutputPort()); - - if(use_image_interpolation) - { - // turns the 3d grid of sampled values into a polygon mesh for rendering, - // by making a surface that contours the volume at a specified level - vtkSmartPointer surface = vtkSmartPointer::New(); - surface->SetInputConnection(to_point_data->GetOutputPort()); - surface->SetValue(0, contour_level); - - vtkSmartPointer append = vtkSmartPointer::New(); - append->AddInputConnection(surface->GetOutputPort()); - - if (cap_contour) - { - // pad outside the volume with zero so that the contour caps the ends instead of leaving holes - vtkSmartPointer cap_pad = vtkSmartPointer::New(); - cap_pad->SetInputConnection(to_point_data->GetOutputPort()); - cap_pad->SetOutputWholeExtent(extent[0] - 1, extent[1] + 2, extent[2] - 1, extent[3] + 2, extent[4] - 1, extent[5] + 2); - if (invert_contour_cap) - { - cap_pad->SetConstant(high + (high - low)); - } - else - { - cap_pad->SetConstant(low + (low - high)); - } - - // again make the same contour surface - vtkSmartPointer cap_surface = vtkSmartPointer::New(); - cap_surface->SetInputConnection(cap_pad->GetOutputPort()); - cap_surface->SetValue(0, contour_level); - - // clip away the internal parts of the volume, to leave only the caps - vtkSmartPointer box = vtkSmartPointer::New(); - double* bounds = image->GetBounds(); - box->SetBounds(bounds[0], bounds[1] + 1, bounds[2], bounds[3] + 1, bounds[4], bounds[5] + 1); - vtkSmartPointer gf = vtkSmartPointer::New(); - gf->SetInputConnection(cap_surface->GetOutputPort()); - gf->SetImplicitFunction(box); - gf->SetExtractInside(0); - - // throw away the normals from the volume, to leave flat sharp normals on the caps - vtkSmartPointer normals = vtkSmartPointer::New(); - normals->SetInputConnection(gf->GetOutputPort()); - normals->SetFeatureAngle(5); - - // add the caps to the scene with their own normals - append->AddInputConnection(normals->GetOutputPort()); - } - - mapper->SetInputConnection(append->GetOutputPort()); - mapper->ScalarVisibilityOff(); - } - else - { - // render as cubes, Minecraft-style - vtkSmartPointer threshold = vtkSmartPointer::New(); - threshold->SetInputConnection(merge_datasets->GetOutputPort()); - threshold->SetInputArrayToProcess(0, 0, 0, - vtkDataObject::FIELD_ASSOCIATION_CELLS, - vtkDataSetAttributes::SCALARS); - threshold->ThresholdByUpper(contour_level); - - vtkSmartPointer geometry = vtkSmartPointer::New(); - geometry->SetInputConnection(threshold->GetOutputPort()); - - mapper->SetInputConnection(geometry->GetOutputPort()); - } - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->SetColor(surface_r,surface_g,surface_b); - actor->GetProperty()->SetAmbient(0.1); - actor->GetProperty()->SetDiffuse(0.5); - actor->GetProperty()->SetSpecular(0.4); - actor->GetProperty()->SetSpecularPower(10); - if(use_wireframe) - actor->GetProperty()->SetRepresentationToWireframe(); - if(show_cell_edges && !use_image_interpolation) - { - actor->GetProperty()->EdgeVisibilityOn(); - actor->GetProperty()->SetEdgeColor(0,0,0); - } - vtkSmartPointer bfprop = vtkSmartPointer::New(); - actor->SetBackfaceProperty(bfprop); - bfprop->SetColor(0.7,0.6,0.55); - bfprop->SetAmbient(0.1); - bfprop->SetDiffuse(0.5); - bfprop->SetSpecular(0.4); - bfprop->SetSpecularPower(10); - actor->SetPosition(offset); - - // add the actor to the renderer's scene - actor->PickableOff(); // not sure about this - sometimes it is nice to paint on the contoured surface too, for 3d sculpting - pRenderer->AddActor(actor); - - // add the bounding box - if(show_bounding_box) - { - vtkSmartPointer box = vtkSmartPointer::New(); - box->SetBounds(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); - - vtkSmartPointer edges = vtkSmartPointer::New(); - edges->SetInputConnection(box->GetOutputPort()); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(edges->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->SetColor(0,0,0); - actor->GetProperty()->SetAmbient(1); - actor->SetPosition(offset); - actor->PickableOff(); - - pRenderer->AddActor(actor); - } - - // add a 2D slice too - if(slice_3D) - { - vtkSmartPointer plane = vtkSmartPointer::New(); - double *bounds = image->GetBounds(); - plane->SetOrigin(slice_3D_position*(bounds[1]-bounds[0])+bounds[0], - slice_3D_position*(bounds[3]-bounds[2])+bounds[2], - slice_3D_position*(bounds[5]-bounds[4])+bounds[4]); - if(slice_3D_axis=="x") - plane->SetNormal(1,0,0); - else if(slice_3D_axis=="y") - plane->SetNormal(0,1,0); - else - plane->SetNormal(0,0,1); - vtkSmartPointer cutter = vtkSmartPointer::New(); - cutter->SetCutFunction(plane); - if(use_image_interpolation) - cutter->SetInputConnection(to_point_data->GetOutputPort()); - else - cutter->SetInputConnection(merge_datasets->GetOutputPort()); - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(cutter->GetOutputPort()); - mapper->SetLookupTable(lut); - mapper->UseLookupTableScalarRangeOn(); - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->LightingOff(); - if(show_cell_edges) - { - actor->GetProperty()->EdgeVisibilityOn(); - actor->GetProperty()->SetEdgeColor(0,0,0); // could be a user option - } - actor->SetPosition(offset); - pRenderer->AddActor(actor); - } - - // add a text label - if(show_chemical_label && this->GetNumberOfChemicals()>1) - { - const float text_label_offset = 5.0 + max(this->GetX(), this->GetY()) / 20.0f; - vtkSmartPointer captionActor = vtkSmartPointer::New(); - captionActor->SetAttachmentPoint(offset[0] + this->GetX() / 2, offset[1] - text_label_offset, offset[2]); - captionActor->SetPosition(0, 0); - captionActor->SetCaption(GetChemicalName(iChem).c_str()); - captionActor->BorderOff(); - captionActor->LeaderOff(); - captionActor->SetPadding(0); - captionActor->GetCaptionTextProperty()->SetJustificationToLeft(); - captionActor->GetCaptionTextProperty()->BoldOff(); - captionActor->GetCaptionTextProperty()->ShadowOff(); - captionActor->GetCaptionTextProperty()->ItalicOff(); - captionActor->GetCaptionTextProperty()->SetFontFamilyToArial(); - captionActor->GetCaptionTextProperty()->SetFontSize(16); - captionActor->GetCaptionTextProperty()->SetVerticalJustificationToCentered(); - captionActor->GetTextActor()->SetTextScaleModeToNone(); - pRenderer->AddActor(captionActor); - } - - offset[0] += this->GetX() + x_gap; // the next chemical should appear further to the right - } - - // also add a scalar bar to show how the colors correspond to values - if (show_color_scale) - { - AddScalarBar(pRenderer, lut); - } - - // add a phase plot - if(show_phase_plot && this->GetNumberOfChemicals()>=2) - { - this->AddPhasePlot( pRenderer,this->GetX()/(high-low),low,high,0.0f,this->GetY()+y_gap,0.0f, - iPhasePlotX,iPhasePlotY,iPhasePlotZ); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::AddPhasePlot(vtkRenderer* pRenderer,float scaling,float low,float high,float posX,float posY,float posZ, - int iChemX,int iChemY,int iChemZ) -{ - iChemX = max( 0, min( iChemX, this->GetNumberOfChemicals()-1 ) ); - iChemY = max( 0, min( iChemY, this->GetNumberOfChemicals()-1 ) ); - iChemZ = max( 0, min( iChemZ, this->GetNumberOfChemicals()-1 ) ); - - // ensure plot points remain within a reasonable range (else get view clipping issues) - double minVal = low-(high-low)*100.0; - double maxVal = high+(high-low)*100.0; - - vtkSmartPointer points = vtkSmartPointer::New(); - points->SetNumberOfPoints(this->GetNumberOfCells()); - points->SetRadius(0); - - vtkSmartPointer thresholdXmin = vtkSmartPointer::New(); - thresholdXmin->SetInputData(this->GetImage(iChemX)); - thresholdXmin->ThresholdByLower(minVal); - thresholdXmin->ReplaceInOn(); - thresholdXmin->SetInValue(minVal); - thresholdXmin->ReplaceOutOff(); - vtkSmartPointer thresholdXmax = vtkSmartPointer::New(); - thresholdXmax->SetInputConnection(thresholdXmin->GetOutputPort()); - thresholdXmax->ThresholdByUpper(maxVal); - thresholdXmax->ReplaceInOn(); - thresholdXmax->SetInValue(maxVal); - thresholdXmax->ReplaceOutOff(); - - vtkSmartPointer mergeX = vtkSmartPointer::New(); - mergeX->SetGeometryConnection(points->GetOutputPort()); - mergeX->SetScalarsConnection(thresholdXmax->GetOutputPort()); - - vtkSmartPointer warpX = vtkSmartPointer::New(); - warpX->UseNormalOn(); - warpX->SetNormal(1,0,0); - warpX->SetInputConnection(mergeX->GetOutputPort()); - warpX->SetScaleFactor(scaling); - - vtkSmartPointer thresholdYmin = vtkSmartPointer::New(); - thresholdYmin->SetInputData(this->GetImage(iChemY)); - thresholdYmin->ThresholdByLower(minVal); - thresholdYmin->ReplaceInOn(); - thresholdYmin->SetInValue(minVal); - thresholdYmin->ReplaceOutOff(); - vtkSmartPointer thresholdYmax = vtkSmartPointer::New(); - thresholdYmax->SetInputConnection(thresholdYmin->GetOutputPort()); - thresholdYmax->ThresholdByUpper(maxVal); - thresholdYmax->ReplaceInOn(); - thresholdYmax->SetInValue(maxVal); - thresholdYmax->ReplaceOutOff(); - - vtkSmartPointer mergeY = vtkSmartPointer::New(); - mergeY->SetGeometryConnection(warpX->GetOutputPort()); - mergeY->SetScalarsConnection(thresholdYmax->GetOutputPort()); - - vtkSmartPointer warpY = vtkSmartPointer::New(); - warpY->UseNormalOn(); - warpY->SetNormal(0,1,0); - warpY->SetInputConnection(mergeY->GetOutputPort()); - warpY->SetScaleFactor(scaling); - - vtkSmartPointer glyph = vtkSmartPointer::New(); - - float offsetZ = 0.0f; - if(this->GetNumberOfChemicals()>2) - { - vtkSmartPointer thresholdZmin = vtkSmartPointer::New(); - thresholdZmin->SetInputData(this->GetImage(iChemZ)); - thresholdZmin->ThresholdByLower(minVal); - thresholdZmin->ReplaceInOn(); - thresholdZmin->SetInValue(minVal); - thresholdZmin->ReplaceOutOff(); - vtkSmartPointer thresholdZmax = vtkSmartPointer::New(); - thresholdZmax->SetInputConnection(thresholdZmin->GetOutputPort()); - thresholdZmax->ThresholdByUpper(maxVal); - thresholdZmax->ReplaceInOn(); - thresholdZmax->SetInValue(maxVal); - thresholdZmax->ReplaceOutOff(); - - vtkSmartPointer mergeZ = vtkSmartPointer::New(); - mergeZ->SetGeometryConnection(warpY->GetOutputPort()); - mergeZ->SetScalarsConnection(thresholdZmax->GetOutputPort()); - - vtkSmartPointer warpZ = vtkSmartPointer::New(); - warpZ->UseNormalOn(); - warpZ->SetNormal(0,0,1); - warpZ->SetInputConnection(mergeZ->GetOutputPort()); - warpZ->SetScaleFactor(scaling); - - glyph->SetInputConnection(warpZ->GetOutputPort()); - - offsetZ = low*scaling; - } - else - { - glyph->SetInputConnection(warpY->GetOutputPort()); - } - - vtkSmartPointer trans = vtkSmartPointer::New(); - trans->Scale(1,1,-1); - vtkSmartPointer transFilter = vtkSmartPointer::New(); - transFilter->SetTransform(trans); - transFilter->SetInputConnection(glyph->GetOutputPort()); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(transFilter->GetOutputPort()); - mapper->ScalarVisibilityOff(); - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->GetProperty()->SetAmbient(1); - actor->GetProperty()->SetPointSize(1); - actor->PickableOff(); - actor->SetPosition(posX-low*scaling,posY-low*scaling,posZ+offsetZ); - pRenderer->AddActor(actor); - - // also add the axes - { - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(posX,posX+scaling*(high-low),posY,posY,posZ,posZ); - axis->SetRanges(low,high,0,0,0,0); - axis->UseRangesOn(); - axis->YAxisVisibilityOff(); - axis->ZAxisVisibilityOff(); - axis->SetXLabel(GetChemicalName(iChemX).c_str()); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - } - { - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(posX,posX,posY,posY+(high-low)*scaling,posZ,posZ); - axis->SetRanges(0,0,low,high,0,0); - axis->UseRangesOn(); - axis->XAxisVisibilityOff(); - axis->ZAxisVisibilityOff(); - axis->SetYLabel(GetChemicalName(iChemY).c_str()); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - } - if(this->GetNumberOfChemicals()>2) - { - vtkSmartPointer axis = vtkSmartPointer::New(); - axis->SetCamera(pRenderer->GetActiveCamera()); - axis->SetBounds(posX,posX,posY,posY,posZ,posZ-scaling*(high-low)); - axis->SetRanges(0,0,0,0,low,high); - axis->UseRangesOn(); - axis->XAxisVisibilityOff(); - axis->YAxisVisibilityOff(); - axis->SetZLabel(GetChemicalName(iChemZ).c_str()); - axis->SetLabelFormat("%.2f"); - axis->SetInertia(10000); - axis->SetCornerOffset(0); - axis->SetNumberOfLabels(5); - axis->PickableOff(); - pRenderer->AddActor(axis); - } -} - -// --------------------------------------------------------------------- - -void ImageRD::SaveStartingPattern() -{ - this->GetImage(this->starting_pattern); -} - -// --------------------------------------------------------------------- - -void ImageRD::RestoreStartingPattern() -{ - this->CopyFromImage(this->starting_pattern); - this->timesteps_taken = 0; -} - -// --------------------------------------------------------------------- - -void ImageRD::SetDimensions(int x, int y, int z) -{ - this->AllocateImages(x,y,z,this->GetNumberOfChemicals(),this->data_type); -} - -// --------------------------------------------------------------------- - -void ImageRD::SetNumberOfChemicals(int n, bool reallocate_storage) -{ - const int X = this->GetX(); - const int Y = this->GetY(); - const int Z = this->GetZ(); - if (reallocate_storage) - { - this->DeallocateImages(); - } - if (n == this->n_chemicals) { - return; - } - if (n > this->n_chemicals) - { - while (static_cast(this->images.size()) < n) { - this->images.push_back( AllocateVTKImage(X, Y, Z, this->data_type) ); - this->images.back()->GetPointData()->GetScalars()->FillComponent(0, 0.0); - } - } - else { - this->images.resize(n); - } - this->n_chemicals = n; - this->is_modified = true; -} - -// --------------------------------------------------------------------- - -void ImageRD::SetDimensionsAndNumberOfChemicals(int x,int y,int z,int nc) -{ - this->AllocateImages(x,y,z,nc,this->data_type); -} - -// --------------------------------------------------------------------- - -int ImageRD::GetNumberOfCells() const -{ - return this->GetX() * this->GetY() * this->GetZ(); -} - -// --------------------------------------------------------------------- - -void ImageRD::GetAsMesh(vtkPolyData *out, const Properties &render_settings) const -{ - bool use_image_interpolation = render_settings.GetProperty("use_image_interpolation").GetBool(); - int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - float contour_level = render_settings.GetProperty("contour_level").GetFloat(); - - float low = render_settings.GetProperty("low").GetFloat(); - float high = render_settings.GetProperty("high").GetFloat(); - float vertical_scale_1D = render_settings.GetProperty("vertical_scale_1D").GetFloat(); - float vertical_scale_2D = render_settings.GetProperty("vertical_scale_2D").GetFloat(); - - switch(this->GetArenaDimensionality()) - { - case 1: - { - float scaling = vertical_scale_1D / (high-low); // vertical_scale gives the height of the graph in worldspace units - - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetInputData(this->GetImage(iActiveChemical)); - vtkSmartPointer warp = vtkSmartPointer::New(); - warp->SetInputConnection(plane->GetOutputPort()); - warp->SetScaleFactor(-scaling); - warp->Update(); - out->DeepCopy(warp->GetOutput()); - } - break; - case 2: - { - float scaling = vertical_scale_2D / (high-low); // vertical_scale gives the height of the graph in worldspace units - - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetInputData(this->GetImage(iActiveChemical)); - vtkSmartPointer warp = vtkSmartPointer::New(); - warp->SetInputConnection(plane->GetOutputPort()); - warp->SetScaleFactor(scaling); - vtkSmartPointer normals = vtkSmartPointer::New(); - normals->SetInputConnection(warp->GetOutputPort()); - normals->SplittingOff(); - normals->Update(); - out->DeepCopy(normals->GetOutput()); - } - break; - case 3: - if(use_image_interpolation) - { - // turns the 3d grid of sampled values into a polygon mesh for rendering, - // by making a surface that contours the volume at a specified level - vtkSmartPointer surface = vtkSmartPointer::New(); - surface->SetInputData(this->GetImage(iActiveChemical)); - surface->SetValue(0, contour_level); - surface->Update(); - out->DeepCopy(surface->GetOutput()); - } - else - { - // render as cubes, Minecraft-style - vtkImageData *image = this->GetImage(iActiveChemical); - int *extent = image->GetExtent(); - - vtkSmartPointer pad = vtkSmartPointer::New(); - pad->SetInputData(image); - pad->SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1); - pad->Update(); - pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars()); // a non-pipelined operation - - vtkSmartPointer threshold = vtkSmartPointer::New(); - threshold->SetInputConnection(pad->GetOutputPort()); - threshold->SetInputArrayToProcess(0, 0, 0, - vtkDataObject::FIELD_ASSOCIATION_CELLS, - vtkDataSetAttributes::SCALARS); - threshold->ThresholdByUpper(contour_level); - - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->Translate (-.5, -.5, -.5); - vtkSmartPointer transformModel = vtkSmartPointer::New(); - transformModel->SetTransform(transform); - transformModel->SetInputConnection(threshold->GetOutputPort()); - - vtkSmartPointer geometry = vtkSmartPointer::New(); - geometry->SetInputConnection(transformModel->GetOutputPort()); - geometry->Update(); - - out->DeepCopy(geometry->GetOutput()); - } - break; - } -} - -// --------------------------------------------------------------------- - -void ImageRD::SaveFile(const char* filename,const Properties& render_settings,bool generate_initial_pattern_when_loading) const -{ - // convert the image to named arrays - vtkSmartPointer im = vtkSmartPointer::New(); - im->DeepCopy(this->images.front()); - im->GetPointData()->SetScalars(NULL); - for(int iChem=0;iChemGetNumberOfChemicals();iChem++) - { - vtkSmartPointer da = vtkSmartPointer::Take( vtkDataArray::CreateDataArray( this->data_type ) ); - da->DeepCopy(this->images[iChem]->GetPointData()->GetScalars()); - da->SetName(GetChemicalName(iChem).c_str()); - im->GetPointData()->AddArray(da); - } - - vtkSmartPointer iw = vtkSmartPointer::New(); - iw->SetSystem(this); - iw->SetRenderSettings(&render_settings); - if(generate_initial_pattern_when_loading) - iw->GenerateInitialPatternWhenLoading(); - iw->SetFileName(filename); - iw->SetDataModeToBinary(); // (to match MeshRD::SaveFile()) - iw->SetInputData(im); - iw->Write(); -} - -// -------------------------------------------------------------------------------- - -void ImageRD::GetAs2DImage(vtkImageData *out,const Properties& render_settings) const -{ - int iActiveChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - - // create a lookup table for mapping values to colors - vtkSmartPointer lut = GetColorMap(render_settings); - - // pass the image through the lookup table - vtkSmartPointer image_mapper = vtkSmartPointer::New(); - image_mapper->SetLookupTable(lut); - image_mapper->SetOutputFormatToRGB(); // without this, vtkJPEGWriter writes JPEGs that some software struggles with - switch(this->GetArenaDimensionality()) - { - case 1: - case 2: - image_mapper->SetInputData(this->GetImage(iActiveChemical)); - break; - case 3: - { - string slice_3D_axis = render_settings.GetProperty("slice_3D_axis").GetAxis(); - float slice_3D_position = render_settings.GetProperty("slice_3D_position").GetFloat(); - - // Matrices for axial, coronal, sagittal, oblique view orientations - static double sagittalElements[16] = { // x - 0, 0,-1, 0, - 1, 0, 0, 0, - 0,-1, 0, 0, - 0, 0, 0, 1 }; - static double coronalElements[16] = { // y - 1, 0, 0, 0, - 0, 0, 1, 0, - 0,-1, 0, 0, - 0, 0, 0, 1 }; - static double axialElements[16] = { // z - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 }; - /*static double obliqueElements[16] = { // could get fancy and have slanting slices - 1, 0, 0, 0, - 0, 0.866025, -0.5, 0, - 0, 0.5, 0.866025, 0, - 0, 0, 0, 1 };*/ - // Set the slice orientation - vtkSmartPointer resliceAxes = vtkSmartPointer::New(); - if(slice_3D_axis=="x") - resliceAxes->DeepCopy(sagittalElements); - else if(slice_3D_axis=="y") - resliceAxes->DeepCopy(coronalElements); - else if(slice_3D_axis=="z") - resliceAxes->DeepCopy(axialElements); - resliceAxes->SetElement(0, 3, slice_3D_position * this->GetX()); - resliceAxes->SetElement(1, 3, slice_3D_position * this->GetY()); - resliceAxes->SetElement(2, 3, slice_3D_position * this->GetZ()); - - vtkSmartPointer voi = vtkSmartPointer::New(); - voi->SetInputData(this->GetImage(iActiveChemical)); - voi->SetOutputDimensionality(2); - voi->SetResliceAxes(resliceAxes); - image_mapper->SetInputConnection(voi->GetOutputPort()); - }; - } - image_mapper->Update(); - - out->DeepCopy(image_mapper->GetOutput()); -} - -// -------------------------------------------------------------------------------- - -void ImageRD::SetFrom2DImage(int iChemical, vtkImageData *im) -{ - if (this->images.front()->GetDimensions()[0] != im->GetDimensions()[0] || - this->images.front()->GetDimensions()[1] != im->GetDimensions()[1] || - this->images.front()->GetDimensions()[2] != im->GetDimensions()[2] || - im->GetPointData()->GetNumberOfComponents() != 1 || - im->GetPointData()->GetNumberOfArrays() != 1) - { - throw runtime_error("ImageRD::SetFrom2DImage : size mismatch"); - } - this->images[iChemical]->GetPointData()->DeepCopy(im->GetPointData()); - this->images[iChemical]->Modified(); - this->undo_stack.clear(); -} - -// -------------------------------------------------------------------------------- - -float ImageRD::GetValue(float x,float y,float z,const Properties& render_settings) -{ - const int X = this->GetX(); - const int Y = this->GetY(); - const int Z = this->GetZ(); - - // which chemical was clicked-on? - float offset_x = 0.0f; - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - int iChemical; - if(show_multiple_chemicals && this->GetArenaDimensionality()==1) - { - // detect which chemical was drawn on from the click position - const double image_height = X / this->image_ratio1D; - iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - } - else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) - { - // detect which chemical was drawn on from the click position - const float x_gap = this->x_spacing_proportion * this->GetX(); - iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - offset_x = iChemical * (X + x_gap); - } - else - { - // only one chemical is shown, must be that one - iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - } - - int ix,iy,iz; - ix = int(floor(x-offset_x)); - iy = int(floor(y)); - iz = int(floor(z)); - ix = min(X-1,max(0,ix)); - iy = min(Y-1,max(0,iy)); - iz = min(Z-1,max(0,iz)); - - return this->GetImage(iChemical)->GetScalarComponentAsFloat(ix,iy,iz,0); -} - -// -------------------------------------------------------------------------------- - -void ImageRD::SetValue(float x,float y,float z,float val,const Properties& render_settings) -{ - const int X = this->GetX(); - const int Y = this->GetY(); - const int Z = this->GetZ(); - - // which chemical was clicked-on? - float offset_x = 0.0f; - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - int iChemical; - if(show_multiple_chemicals && this->GetArenaDimensionality()==1) - { - // detect which chemical was drawn on from the click position - const double image_height = X / this->image_ratio1D; - iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - } - else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) - { - // detect which chemical was drawn on from the click position - const float x_gap = this->x_spacing_proportion * this->GetX(); - iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - offset_x = iChemical * (X + x_gap); - } - else - { - // only one chemical is shown, must be that one - iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - } - - int ix,iy,iz; - ix = int(floor(x-offset_x)); - iy = int(floor(y)); - iz = int(floor(z)); - ix = min(X-1,max(0,ix)); - iy = min(Y-1,max(0,iy)); - iz = min(Z-1,max(0,iz)); - - float old_val = this->GetImage(iChemical)->GetScalarComponentAsFloat(ix,iy,iz,0); - int ijk[3] = { ix, iy, iz }; - vtkIdType iCell = this->GetImage(iChemical)->ComputeCellId(ijk); - this->StorePaintAction(iChemical,iCell,old_val); - this->GetImage(iChemical)->SetScalarComponentFromFloat(ix,iy,iz,0,val); - this->images[iChemical]->Modified(); - this->is_modified = true; -} - -// -------------------------------------------------------------------------------- - -void ImageRD::SetValuesInRadius(float x,float y,float z,float r,float val,const Properties& render_settings) -{ - const int X = this->GetX(); - const int Y = this->GetY(); - const int Z = this->GetZ(); - - // which chemical was clicked-on? - float offset_x = 0.0f; - bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); - int iChemical; - if(show_multiple_chemicals && this->GetArenaDimensionality()==1) - { - // detect which chemical was drawn on from the click position - const double image_height = X / this->image_ratio1D; - iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - } - else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) - { - // detect which chemical was drawn on from the click position - const float x_gap = this->x_spacing_proportion * this->GetX(); - iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); - iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) - offset_x = iChemical * (X + x_gap); - } - else - { - // only one chemical is shown, must be that one - iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); - } - - double *dataset_bbox = this->images.front()->GetBounds(); - r *= hypot3(dataset_bbox[1]-dataset_bbox[0],dataset_bbox[3]-dataset_bbox[2],dataset_bbox[5]-dataset_bbox[4]); - - int ix,iy,iz; - ix = int(floor(x-offset_x)); - iy = int(floor(y)); - iz = int(floor(z)); - ix = min(X-1,max(0,ix)); - iy = min(Y-1,max(0,iy)); - iz = min(Z-1,max(0,iz)); - - for(int tz=max(0,int(iz-r));tz<=min(Z-1,int(iz+r));tz++) - { - for(int ty=max(0,int(iy-r));ty<=min(Y-1,int(iy+r));ty++) - { - for(int tx=max(0,int(ix-r));tx<=min(X-1,int(ix+r));tx++) - { - if(hypot3(ix-tx,iy-ty,iz-tz)GetImage(iChemical)->GetScalarComponentAsFloat(tx,ty,tz,0); - int ijk[3] = { tx, ty, tz }; - vtkIdType iCell = this->GetImage(iChemical)->ComputeCellId(ijk); - this->StorePaintAction(iChemical,iCell,old_val); - this->GetImage(iChemical)->SetScalarComponentFromFloat(tx,ty,tz,0,val); - } - } - } - } - this->images[iChemical]->Modified(); - this->is_modified = true; -} - -// -------------------------------------------------------------------------------- - -void ImageRD::FlipPaintAction(PaintAction& cca) -{ - float *pCell = static_cast(this->GetImage(cca.iChemical)->GetScalarPointer()) + cca.iCell; - float old_val = *pCell; - *pCell = cca.val; - cca.val = old_val; - cca.done = !cca.done; - this->images[cca.iChemical]->Modified(); -} - -// -------------------------------------------------------------------------------- - -size_t ImageRD::GetMemorySize() const + // pass the image through the lookup table + vtkSmartPointer image_mapper = vtkSmartPointer::New(); + image_mapper->SetLookupTable(lut); + image_mapper->SetOutputFormatToRGB(); // without this, vtkJPEGWriter writes JPEGs that some software struggles with + switch(this->GetArenaDimensionality()) + { + case 1: + case 2: + image_mapper->SetInputData(this->GetImage(iActiveChemical)); + break; + case 3: + { + string slice_3D_axis = render_settings.GetProperty("slice_3D_axis").GetAxis(); + float slice_3D_position = render_settings.GetProperty("slice_3D_position").GetFloat(); + + // Matrices for axial, coronal, sagittal, oblique view orientations + static double sagittalElements[16] = { // x + 0, 0,-1, 0, + 1, 0, 0, 0, + 0,-1, 0, 0, + 0, 0, 0, 1 }; + static double coronalElements[16] = { // y + 1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1 }; + static double axialElements[16] = { // z + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 }; + /*static double obliqueElements[16] = { // could get fancy and have slanting slices + 1, 0, 0, 0, + 0, 0.866025, -0.5, 0, + 0, 0.5, 0.866025, 0, + 0, 0, 0, 1 };*/ + // Set the slice orientation + vtkSmartPointer resliceAxes = vtkSmartPointer::New(); + if(slice_3D_axis=="x") + resliceAxes->DeepCopy(sagittalElements); + else if(slice_3D_axis=="y") + resliceAxes->DeepCopy(coronalElements); + else if(slice_3D_axis=="z") + resliceAxes->DeepCopy(axialElements); + resliceAxes->SetElement(0, 3, slice_3D_position * this->GetX()); + resliceAxes->SetElement(1, 3, slice_3D_position * this->GetY()); + resliceAxes->SetElement(2, 3, slice_3D_position * this->GetZ()); + + vtkSmartPointer voi = vtkSmartPointer::New(); + voi->SetInputData(this->GetImage(iActiveChemical)); + voi->SetOutputDimensionality(2); + voi->SetResliceAxes(resliceAxes); + image_mapper->SetInputConnection(voi->GetOutputPort()); + }; + } + image_mapper->Update(); + + out->DeepCopy(image_mapper->GetOutput()); +} + +// -------------------------------------------------------------------------------- + +void ImageRD::SetFrom2DImage(int iChemical, vtkImageData *im) +{ + if (this->images.front()->GetDimensions()[0] != im->GetDimensions()[0] || + this->images.front()->GetDimensions()[1] != im->GetDimensions()[1] || + this->images.front()->GetDimensions()[2] != im->GetDimensions()[2] || + im->GetPointData()->GetNumberOfComponents() != 1 || + im->GetPointData()->GetNumberOfArrays() != 1) + { + throw runtime_error("ImageRD::SetFrom2DImage : size mismatch"); + } + this->images[iChemical]->GetPointData()->DeepCopy(im->GetPointData()); + this->images[iChemical]->Modified(); + this->undo_stack.clear(); +} + +// -------------------------------------------------------------------------------- + +float ImageRD::GetValue(float x,float y,float z,const Properties& render_settings) +{ + const int X = this->GetX(); + const int Y = this->GetY(); + const int Z = this->GetZ(); + + // which chemical was clicked-on? + float offset_x = 0.0f; + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + int iChemical; + if(show_multiple_chemicals && this->GetArenaDimensionality()==1) + { + // detect which chemical was drawn on from the click position + const double image_height = X / this->image_ratio1D; + iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + } + else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) + { + // detect which chemical was drawn on from the click position + const float x_gap = this->x_spacing_proportion * this->GetX(); + iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + offset_x = iChemical * (X + x_gap); + } + else + { + // only one chemical is shown, must be that one + iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + } + + int ix,iy,iz; + ix = int(floor(x-offset_x)); + iy = int(floor(y)); + iz = int(floor(z)); + ix = min(X-1,max(0,ix)); + iy = min(Y-1,max(0,iy)); + iz = min(Z-1,max(0,iz)); + + return this->GetImage(iChemical)->GetScalarComponentAsFloat(ix,iy,iz,0); +} + +// -------------------------------------------------------------------------------- + +void ImageRD::SetValue(float x,float y,float z,float val,const Properties& render_settings) +{ + const int X = this->GetX(); + const int Y = this->GetY(); + const int Z = this->GetZ(); + + // which chemical was clicked-on? + float offset_x = 0.0f; + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + int iChemical; + if(show_multiple_chemicals && this->GetArenaDimensionality()==1) + { + // detect which chemical was drawn on from the click position + const double image_height = X / this->image_ratio1D; + iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + } + else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) + { + // detect which chemical was drawn on from the click position + const float x_gap = this->x_spacing_proportion * this->GetX(); + iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + offset_x = iChemical * (X + x_gap); + } + else + { + // only one chemical is shown, must be that one + iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + } + + int ix,iy,iz; + ix = int(floor(x-offset_x)); + iy = int(floor(y)); + iz = int(floor(z)); + ix = min(X-1,max(0,ix)); + iy = min(Y-1,max(0,iy)); + iz = min(Z-1,max(0,iz)); + + float old_val = this->GetImage(iChemical)->GetScalarComponentAsFloat(ix,iy,iz,0); + int ijk[3] = { ix, iy, iz }; + vtkIdType iCell = this->GetImage(iChemical)->ComputeCellId(ijk); + this->StorePaintAction(iChemical,iCell,old_val); + this->GetImage(iChemical)->SetScalarComponentFromFloat(ix,iy,iz,0,val); + this->images[iChemical]->Modified(); + this->is_modified = true; +} + +// -------------------------------------------------------------------------------- + +void ImageRD::SetValuesInRadius(float x,float y,float z,float r,float val,const Properties& render_settings) +{ + const int X = this->GetX(); + const int Y = this->GetY(); + const int Z = this->GetZ(); + + // which chemical was clicked-on? + float offset_x = 0.0f; + bool show_multiple_chemicals = render_settings.GetProperty("show_multiple_chemicals").GetBool(); + int iChemical; + if(show_multiple_chemicals && this->GetArenaDimensionality()==1) + { + // detect which chemical was drawn on from the click position + const double image_height = X / this->image_ratio1D; + iChemical = int(floor((- y + this->image_top1D + image_height)/(image_height*2))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + } + else if(show_multiple_chemicals && this->GetArenaDimensionality()>=2) + { + // detect which chemical was drawn on from the click position + const float x_gap = this->x_spacing_proportion * this->GetX(); + iChemical = int(floor((x + x_gap / 2) / (X + x_gap))); + iChemical = min(this->GetNumberOfChemicals()-1,max(0,iChemical)); // clamp to allowed range (just in case) + offset_x = iChemical * (X + x_gap); + } + else + { + // only one chemical is shown, must be that one + iChemical = IndexFromChemicalName(render_settings.GetProperty("active_chemical").GetChemical()); + } + + double *dataset_bbox = this->images.front()->GetBounds(); + r *= hypot3(dataset_bbox[1]-dataset_bbox[0],dataset_bbox[3]-dataset_bbox[2],dataset_bbox[5]-dataset_bbox[4]); + + int ix,iy,iz; + ix = int(floor(x-offset_x)); + iy = int(floor(y)); + iz = int(floor(z)); + ix = min(X-1,max(0,ix)); + iy = min(Y-1,max(0,iy)); + iz = min(Z-1,max(0,iz)); + + for(int tz=max(0,int(iz-r));tz<=min(Z-1,int(iz+r));tz++) + { + for(int ty=max(0,int(iy-r));ty<=min(Y-1,int(iy+r));ty++) + { + for(int tx=max(0,int(ix-r));tx<=min(X-1,int(ix+r));tx++) + { + if(hypot3(ix-tx,iy-ty,iz-tz)GetImage(iChemical)->GetScalarComponentAsFloat(tx,ty,tz,0); + int ijk[3] = { tx, ty, tz }; + vtkIdType iCell = this->GetImage(iChemical)->ComputeCellId(ijk); + this->StorePaintAction(iChemical,iCell,old_val); + this->GetImage(iChemical)->SetScalarComponentFromFloat(tx,ty,tz,0,val); + } + } + } + } + this->images[iChemical]->Modified(); + this->is_modified = true; +} + +// -------------------------------------------------------------------------------- + +void ImageRD::FlipPaintAction(PaintAction& cca) +{ + float *pCell = static_cast(this->GetImage(cca.iChemical)->GetScalarPointer()) + cca.iCell; + float old_val = *pCell; + *pCell = cca.val; + cca.val = old_val; + cca.done = !cca.done; + this->images[cca.iChemical]->Modified(); +} + +// -------------------------------------------------------------------------------- + +size_t ImageRD::GetMemorySize() const { return this->n_chemicals * this->data_type_size * this->GetX() * this->GetY() * this->GetZ(); } -// -------------------------------------------------------------------------------- - -vector ImageRD::GetData(int i_chemical) const -{ - vector values(this->GetX() * this->GetY() * this->GetZ()); - size_t i = 0; - for(int z = 0; z < this->GetZ(); z++) - { - for (int y = 0; y < this->GetY(); y++) - { - for (int x = 0; x < this->GetX(); x++) - { - values[i++] = this->images[i_chemical]->GetScalarComponentAsFloat(x, y, z, 0); - } - } - } - return values; -} - -// -------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------- + +vector ImageRD::GetData(int i_chemical) const +{ + vector values(this->GetX() * this->GetY() * this->GetZ()); + size_t i = 0; + for(int z = 0; z < this->GetZ(); z++) + { + for (int y = 0; y < this->GetY(); y++) + { + for (int x = 0; x < this->GetX(); x++) + { + values[i++] = this->images[i_chemical]->GetScalarComponentAsFloat(x, y, z, 0); + } + } + } + return values; +} + +// -------------------------------------------------------------------------------- diff --git a/src/readybase/ImageRD.hpp b/src/readybase/ImageRD.hpp index b99a51333..ad23f1469 100644 --- a/src/readybase/ImageRD.hpp +++ b/src/readybase/ImageRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/InitialPatternGenerator.cpp b/src/readybase/InitialPatternGenerator.cpp index d12f18063..4ead48ee6 100644 --- a/src/readybase/InitialPatternGenerator.cpp +++ b/src/readybase/InitialPatternGenerator.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/InitialPatternGenerator.hpp b/src/readybase/InitialPatternGenerator.hpp index dd3265eb2..52ae9f276 100644 --- a/src/readybase/InitialPatternGenerator.hpp +++ b/src/readybase/InitialPatternGenerator.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/MeshGenerators.cpp b/src/readybase/MeshGenerators.cpp index 9efd0620a..365f66940 100644 --- a/src/readybase/MeshGenerators.cpp +++ b/src/readybase/MeshGenerators.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/MeshGenerators.hpp b/src/readybase/MeshGenerators.hpp index 694ed391f..3be3b4a4b 100644 --- a/src/readybase/MeshGenerators.hpp +++ b/src/readybase/MeshGenerators.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/MeshRD.cpp b/src/readybase/MeshRD.cpp index 7ef1b39da..687840025 100644 --- a/src/readybase/MeshRD.cpp +++ b/src/readybase/MeshRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. @@ -362,7 +362,12 @@ void MeshRD::InitializeRenderPipeline(vtkRenderer* pRenderer,const Properties& r assign_attribute->Assign(chem.c_str(), vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); vtkSmartPointer threshold = vtkSmartPointer::New(); threshold->SetInputConnection(assign_attribute->GetOutputPort()); +#if VTK_MAJOR_VERSION > 9 || (VTK_MAJOR_VERSION == 9 && VTK_MINOR_VERSION >= 1) + threshold->SetUpperThreshold(contour_level); + threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER); +#else threshold->ThresholdByUpper(contour_level); +#endif vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputConnection(threshold->GetOutputPort()); mapper->SetLookupTable(lut); @@ -839,7 +844,12 @@ void MeshRD::GetAsMesh(vtkPolyData *out, const Properties &render_settings) cons assign_attribute->Assign(activeChemical.c_str(), vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA); vtkSmartPointer threshold = vtkSmartPointer::New(); threshold->SetInputConnection(assign_attribute->GetOutputPort()); +#if VTK_MAJOR_VERSION > 9 || (VTK_MAJOR_VERSION == 9 && VTK_MINOR_VERSION >= 1) + threshold->SetUpperThreshold(contour_level); + threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER); +#else threshold->ThresholdByUpper(contour_level); +#endif vtkSmartPointer geom = vtkSmartPointer::New(); geom->SetInputConnection(threshold->GetOutputPort()); geom->Update(); diff --git a/src/readybase/MeshRD.hpp b/src/readybase/MeshRD.hpp index 5a46f39de..1d29a30cf 100644 --- a/src/readybase/MeshRD.hpp +++ b/src/readybase/MeshRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCLImageRD.cpp b/src/readybase/OpenCLImageRD.cpp index f47eb77c9..dff748b8a 100644 --- a/src/readybase/OpenCLImageRD.cpp +++ b/src/readybase/OpenCLImageRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCLImageRD.hpp b/src/readybase/OpenCLImageRD.hpp index d603dbf53..f30860e26 100644 --- a/src/readybase/OpenCLImageRD.hpp +++ b/src/readybase/OpenCLImageRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCLMeshRD.cpp b/src/readybase/OpenCLMeshRD.cpp index e988f649f..edd9ffbfb 100644 --- a/src/readybase/OpenCLMeshRD.cpp +++ b/src/readybase/OpenCLMeshRD.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCLMeshRD.hpp b/src/readybase/OpenCLMeshRD.hpp index fbab697ac..c57f8fd22 100644 --- a/src/readybase/OpenCLMeshRD.hpp +++ b/src/readybase/OpenCLMeshRD.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCL_MixIn.cpp b/src/readybase/OpenCL_MixIn.cpp index 22f66e678..6649d46dd 100644 --- a/src/readybase/OpenCL_MixIn.cpp +++ b/src/readybase/OpenCL_MixIn.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCL_MixIn.hpp b/src/readybase/OpenCL_MixIn.hpp index 41d3d4c48..2325d4981 100644 --- a/src/readybase/OpenCL_MixIn.hpp +++ b/src/readybase/OpenCL_MixIn.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCL_utils.cpp b/src/readybase/OpenCL_utils.cpp index 3981db493..4c2682219 100644 --- a/src/readybase/OpenCL_utils.cpp +++ b/src/readybase/OpenCL_utils.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/OpenCL_utils.hpp b/src/readybase/OpenCL_utils.hpp index 45c26ec01..50e89263a 100644 --- a/src/readybase/OpenCL_utils.hpp +++ b/src/readybase/OpenCL_utils.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/Properties.cpp b/src/readybase/Properties.cpp index 1b4a27ce2..758300dbb 100644 --- a/src/readybase/Properties.cpp +++ b/src/readybase/Properties.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/Properties.hpp b/src/readybase/Properties.hpp index 4b1b7db79..a2437ee22 100644 --- a/src/readybase/Properties.hpp +++ b/src/readybase/Properties.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/SystemFactory.cpp b/src/readybase/SystemFactory.cpp index ac433c735..38895820d 100644 --- a/src/readybase/SystemFactory.cpp +++ b/src/readybase/SystemFactory.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/SystemFactory.hpp b/src/readybase/SystemFactory.hpp index c92ff3f6f..c736c65c4 100644 --- a/src/readybase/SystemFactory.hpp +++ b/src/readybase/SystemFactory.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/overlays.cpp b/src/readybase/overlays.cpp index e96ce16f3..d3856bb35 100644 --- a/src/readybase/overlays.cpp +++ b/src/readybase/overlays.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. @@ -48,19 +48,19 @@ Overlay::Overlay(vtkXMLDataElement* node) : XML_Object(node) // is this an operation element? unique_ptr pOp = BaseOperation::New(subnode); if(pOp) { - this->op = move(pOp); // TODO: check if already supplied + this->op = std::move(pOp); // TODO: check if already supplied continue; // (save time parsing as other types) } // is this a fill element? unique_ptr pFill = BaseFill::New(subnode); if(pFill) { - this->fill = move(pFill); // TODO: check if already supplied + this->fill = std::move(pFill); // TODO: check if already supplied continue; } // must be a shape element? unique_ptr pShape = BaseShape::New(subnode); if(pShape) - this->shapes.push_back(move(pShape)); + this->shapes.push_back(std::move(pShape)); else throw runtime_error(string("Unknown overlay element: ")+subnode->GetName()); } if(!this->op) throw runtime_error("overlay: missing operation element"); @@ -358,7 +358,7 @@ class PerlinNoise: public BaseFill read_optional_attribute(node, "num_octaves", this->num_octaves); } - void Reseed() + void Reseed() override { this->perlin.reseed(static_cast(time(NULL))); } diff --git a/src/readybase/overlays.hpp b/src/readybase/overlays.hpp index ca86701fd..ca403c369 100644 --- a/src/readybase/overlays.hpp +++ b/src/readybase/overlays.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/scene_items.cpp b/src/readybase/scene_items.cpp index aab352e0d..ab62ca9cf 100644 --- a/src/readybase/scene_items.cpp +++ b/src/readybase/scene_items.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/scene_items.hpp b/src/readybase/scene_items.hpp index e28ac23ef..7f42d85fa 100644 --- a/src/readybase/scene_items.hpp +++ b/src/readybase/scene_items.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/stencils.cpp b/src/readybase/stencils.cpp index cb001c7d4..ed811b9a4 100644 --- a/src/readybase/stencils.cpp +++ b/src/readybase/stencils.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/stencils.hpp b/src/readybase/stencils.hpp index ac4ed1ad3..c83a945fa 100644 --- a/src/readybase/stencils.hpp +++ b/src/readybase/stencils.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/utils.cpp b/src/readybase/utils.cpp index 3c37bb2c6..487f0a14c 100644 --- a/src/readybase/utils.cpp +++ b/src/readybase/utils.cpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready. diff --git a/src/readybase/utils.hpp b/src/readybase/utils.hpp index 47e61475c..dcfed3028 100644 --- a/src/readybase/utils.hpp +++ b/src/readybase/utils.hpp @@ -1,4 +1,4 @@ -/* Copyright 2011-2021 The Ready Bunch +/* Copyright 2011-2024 The Ready Bunch This file is part of Ready.