diff --git a/application/testing/CMakeLists.txt b/application/testing/CMakeLists.txt index 3561301450..1f0a5c17ea 100644 --- a/application/testing/CMakeLists.txt +++ b/application/testing/CMakeLists.txt @@ -186,7 +186,7 @@ f3d_test(NAME TestVolumeMag DATA vase_4comp.vti ARGS -vb LONG_TIMEOUT) f3d_test(NAME TestVolumeComp DATA vase_4comp.vti ARGS -vb --comp=3 LONG_TIMEOUT) f3d_test(NAME TestVolumeDirect DATA vase_4comp.vti ARGS -vb --comp=-2 LONG_TIMEOUT) f3d_test(NAME TestVolumeCells DATA waveletArrays.vti ARGS -vb --cells LONG_TIMEOUT) -f3d_test(NAME TestVolumeNonScalars DATA waveletArrays.vti ARGS -vb -s --coloring-array=RandomPointScalars LONG_TIMEOUT) +f3d_test(NAME TestVolumeColoringArray DATA waveletArrays.vti ARGS -vb --coloring-array=Result LONG_TIMEOUT) f3d_test(NAME TestTextureNormal DATA WaterBottle.glb ARGS --texture-normal=${F3D_SOURCE_DIR}/testing/data/normal.png --normal-scale=0.1) f3d_test(NAME TestTextureMaterial DATA WaterBottle.glb ARGS --texture-material=${F3D_SOURCE_DIR}/testing/data/red_mod.jpg --roughness=1 --metallic=1) f3d_test(NAME TestTextureMaterialWithOptions DATA WaterBottle.glb ARGS --texture-material=${F3D_SOURCE_DIR}/testing/data/red_mod.jpg --roughness=0.5 --metallic=0.5) @@ -221,6 +221,7 @@ f3d_test(NAME TestMultiFileColoring DATA mb/recursive ARGS --multi-file-mode=all f3d_test(NAME TestMultiFileVolume DATA multi ARGS --multi-file-mode=all -vsb --coloring-array=Scalars_) f3d_test(NAME TestMultiFileColoringTexture DATA mb/recursive/mb_1_0.vtp mb/recursive/mb_2_0.vtp world.obj ARGS --multi-file-mode=all -sb --coloring-array=Normals --comp=1) f3d_test(NAME TestMultiFilePositionals DATA mb/recursive/mb_0_0.vtu mb/recursive/mb_1_0.vtp ARGS --multi-file-mode=all -s --coloring-array=Polynomial -b) +f3d_test(NAME TestMultiFileNonCoherentComponentNames DATA bluntfin.vts bluntfin_t.vtu ARGS --multi-file-mode=all --scalar-coloring --coloring-array=Momentum --comp=2 --bar) f3d_test(NAME TestMultiInputArg ARGS --input ${F3D_SOURCE_DIR}/testing/data/mb/recursive/mb_0_0.vtu ${F3D_SOURCE_DIR}/testing/data/mb/recursive/mb_1_0.vtp --multi-file-mode=all -s --coloring-array=Polynomial -b) f3d_test(NAME TestMultiInputMultiArgs ARGS --input ${F3D_SOURCE_DIR}/testing/data/mb/recursive/mb_0_0.vtu --input ${F3D_SOURCE_DIR}/testing/data/mb/recursive/mb_1_0.vtp --multi-file-mode=all -s --coloring-array=Polynomial -b) f3d_test(NAME TestInvalidUpDirection DATA suzanne.ply ARGS -g --up=W REGEXP "W is not a valid up direction" NO_BASELINE) @@ -753,6 +754,8 @@ f3d_test(NAME TestInteractionCycleCell DATA waveletArrays.vti INTERACTION) #VCCC f3d_test(NAME TestInteractionCycleComp DATA dragon.vtu INTERACTION) #SYYYY f3d_test(NAME TestInteractionCycleScalars DATA dragon.vtu INTERACTION) #BSSSS f3d_test(NAME TestInteractionCycleCellInvalidIndex DATA waveletArrays.vti INTERACTION) #SSC +f3d_test(NAME TestInteractionVolumeCycle DATA waveletArrays.vti ARGS INTERACTION) #VSS +f3d_test(NAME TestInteractionVolumeAfterColoring DATA waveletArrays.vti ARGS INTERACTION) #SSSV f3d_test(NAME TestInteractionVolumeInverse DATA HeadMRVolume.mhd ARGS --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 INTERACTION) #VI f3d_test(NAME TestInteractionMultiFileVolume DATA multi ARGS --multi-file-mode=all INTERACTION) #SSVB f3d_test(NAME TestInteractionPointCloud DATA pointsCloud.vtp ARGS --point-sprites-size=20 INTERACTION) #O @@ -863,6 +866,9 @@ f3d_test(NAME TestVerboseWrongArray DATA dragon.vtu ARGS -s --coloring-array=dum # Default scalar array verbosity test f3d_test(NAME TestVerboseDefaultScalar DATA HeadMRVolume.mhd ARGS -s --verbose REGEXP "Coloring using point array named MetaImage, Magnitude" NO_BASELINE) +# Volume array verbosity test +f3d_test(NAME TestVerboseVolume DATA HeadMRVolume.mhd ARGS -v --verbose REGEXP "Coloring using point array named MetaImage .forced., Magnitude" NO_BASELINE) + # Incorrect component test f3d_test(NAME TestIncorrectComponent DATA dragon.vtu ARGS -s --comp=4 REGEXP "Invalid component index: 4" NO_BASELINE) @@ -997,6 +1003,9 @@ f3d_test(NAME TestVersion ARGS --version REGEXP "Version:") # Test readers-list display f3d_test(NAME TestReadersList ARGS --readers-list REGEXP_FAIL "No registered reader found") +# Test invalid component string coverage +f3d_test(NAME TestInteractionInvalidComponent INTERACTION DATA cow.vtp ARGS --comp=1 NO_BASELINE) #H + # Test multi plugin readers-lists if(F3D_PLUGIN_BUILD_ALEMBIC AND F3D_PLUGIN_BUILD_ASSIMP) f3d_test(NAME TestReadersListMultiplePlugins ARGS --readers-list --load-plugins=assimp,alembic NO_BASELINE REGEXP_FAIL "Plugin failed to load") diff --git a/doc/libf3d/OPTIONS.md b/doc/libf3d/OPTIONS.md index f55523fa6b..5a8f531c2e 100644 --- a/doc/libf3d/OPTIONS.md +++ b/doc/libf3d/OPTIONS.md @@ -62,7 +62,7 @@ model.scivis.range|vector\
optional
render|Set the *coloring rang model.point_sprites.enable|bool
false
render|Show sphere *points sprites* instead of the geometry.|\-\-point-sprites model.point_sprites.type|string
sphere
render|Set the sprites type when showing point sprites (can be `sphere` or `gaussian`).|\-\-point-stripes-type model.point_sprites.size|double
10.0
render|Set the *size* of point sprites.|\-\-point-stripes-size -model.volume.enable|bool
false
render|Enable *volume rendering*. It is only available for 3D image data (vti, dcm, nrrd, mhd files) and will display nothing with other formats.|\-\-volume +model.volume.enable|bool
false
render|Enable *volume rendering*. It is only available for 3D image data (vti, dcm, nrrd, mhd files) and will display nothing with other formats. It forces coloring.|\-\-volume model.volume.inverse|bool
false
render|Inverse the linear opacity function.|\-\-inverse ## Render Options diff --git a/doc/user/INTERACTIONS.md b/doc/user/INTERACTIONS.md index beef373793..2652dadf53 100644 --- a/doc/user/INTERACTIONS.md +++ b/doc/user/INTERACTIONS.md @@ -30,7 +30,7 @@ Other options can be toggled directly by pressing the following hotkeys: * W: cycle animations. * B: display of the scalar bar, only when coloring and not using direct scalars. -* V: volume rendering. +* V: volume rendering, forces coloring. * I: opacity function inversion during volume rendering. * O: point sprites rendering. * P: translucency support. diff --git a/doc/user/OPTIONS.md b/doc/user/OPTIONS.md index d1426f4992..1d59981da0 100644 --- a/doc/user/OPTIONS.md +++ b/doc/user/OPTIONS.md @@ -96,7 +96,7 @@ Options|Default|Description -b, \-\-bar||Show *scalar bar* of the coloring by array.
Use with the scalar option. \-\-colormap\-file=\||Set a *colormap file for the coloring*.
See [color maps](COLOR_MAPS.md).
Use with the scalar option. \-\-colormap=\||Set a *custom colormap for the coloring*.
This is a list of colors in the format `val1,red1,green1,blue1,...,valN,redN,greenN,blueN`
where all values are in the range (0,1).
Ignored if `--colormap-file` option is specified.
Use with the scalar option. --v, \-\-volume||Enable *volume rendering*. It is only available for 3D image data (vti, dcm, nrrd, mhd files) and will display nothing with other formats. +-v, \-\-volume||Enable *volume rendering*. It is only available for 3D image data (vti, dcm, nrrd, mhd files) and will display nothing with other formats. It forces coloring. -i, \-\-inverse||Inverse the linear opacity function used for volume rendering. ## Camera configuration options diff --git a/library/src/interactor_impl.cxx b/library/src/interactor_impl.cxx index eb46de7f88..a50812168d 100644 --- a/library/src/interactor_impl.cxx +++ b/library/src/interactor_impl.cxx @@ -176,6 +176,7 @@ class interactor_impl::internals vtkRenderWindow* renWin = self->Window.GetRenderWindow(); vtkF3DRenderer* ren = vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer()); bool checkColoring = false; + bool printColoring = false; bool render = false; // Available keycodes: None @@ -190,28 +191,28 @@ class interactor_impl::internals case 'C': if (ren) { - ren->CycleScalars(vtkF3DRenderer::CycleType::FIELD); - self->Window.PrintColoringDescription(log::VerboseLevel::DEBUG); + ren->CycleFieldForColoring(); checkColoring = true; render = true; + printColoring = true; } break; case 'S': if (ren) { - ren->CycleScalars(vtkF3DRenderer::CycleType::ARRAY_INDEX); - self->Window.PrintColoringDescription(log::VerboseLevel::DEBUG); + ren->CycleArrayForColoring(); checkColoring = true; render = true; + printColoring = true; } break; case 'Y': if (ren) { - ren->CycleScalars(vtkF3DRenderer::CycleType::COMPONENT); - self->Window.PrintColoringDescription(log::VerboseLevel::DEBUG); + ren->CycleComponentForColoring(); checkColoring = true; render = true; + printColoring = true; } break; case 'B': @@ -273,6 +274,7 @@ class interactor_impl::internals case 'V': self->Options.model.volume.enable = !self->Options.model.volume.enable; render = true; + printColoring = true; break; case 'I': self->Options.model.volume.inverse = !self->Options.model.volume.inverse; @@ -379,15 +381,19 @@ class interactor_impl::internals if (checkColoring) { // Resynchronise renderer coloring status with options - self->Options.model.scivis.enable = ren->GetColoringEnabled(); - self->Options.model.scivis.cells = ren->GetColoringUseCell(); - self->Options.model.scivis.array_name = ren->GetColoringArrayName(); - self->Options.model.scivis.component = ren->GetColoringComponent(); + self->Options.model.scivis.enable = ren->GetEnableColoring(); + self->Options.model.scivis.cells = ren->GetUseCellColoring(); + self->Options.model.scivis.array_name = ren->GetArrayNameForColoring(); + self->Options.model.scivis.component = ren->GetComponentForColoring(); } if (render) { self->Window.render(); } + if (printColoring) + { + self->Window.PrintColoringDescription(log::VerboseLevel::DEBUG); + } } static void OnDropFiles(vtkObject*, unsigned long, void* clientData, void* callData) diff --git a/library/src/window_impl.cxx b/library/src/window_impl.cxx index 47483cd037..33ff621822 100644 --- a/library/src/window_impl.cxx +++ b/library/src/window_impl.cxx @@ -533,8 +533,11 @@ void window_impl::UpdateDynamicOptions() renderer->SetNormalScale(opt.model.normal.scale); renderer->SetTextureMatCap(opt.model.matcap.texture); - renderer->SetColoring(opt.model.scivis.enable, opt.model.scivis.cells, - opt.model.scivis.array_name, opt.model.scivis.component); + renderer->SetEnableColoring(opt.model.scivis.enable); + renderer->SetUseCellColoring(opt.model.scivis.cells); + renderer->SetArrayNameForColoring(opt.model.scivis.array_name); + renderer->SetComponentForColoring(opt.model.scivis.component); + renderer->SetScalarBarRange(opt.model.scivis.range); renderer->SetColormap(opt.model.scivis.colormap); renderer->ShowScalarBar(opt.ui.scalar_bar); diff --git a/testing/baselines/TestInteractionVolumeAfterColoring.png b/testing/baselines/TestInteractionVolumeAfterColoring.png new file mode 100644 index 0000000000..15eb2cf6c5 --- /dev/null +++ b/testing/baselines/TestInteractionVolumeAfterColoring.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d5c0729f018024243918690289e8a73b61f8e844ac939a0c81d6aeedb91ade9 +size 80342 diff --git a/testing/baselines/TestInteractionVolumeCycle.png b/testing/baselines/TestInteractionVolumeCycle.png new file mode 100644 index 0000000000..15eb2cf6c5 --- /dev/null +++ b/testing/baselines/TestInteractionVolumeCycle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d5c0729f018024243918690289e8a73b61f8e844ac939a0c81d6aeedb91ade9 +size 80342 diff --git a/testing/baselines/TestMultiFileNonCoherentComponentNames.png b/testing/baselines/TestMultiFileNonCoherentComponentNames.png new file mode 100644 index 0000000000..b6c4c9f89a --- /dev/null +++ b/testing/baselines/TestMultiFileNonCoherentComponentNames.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:837d60136b5004b0153c3dc7134951a98759ea2abcb0848d6be2505ac386d0a1 +size 13943 diff --git a/testing/baselines/TestVolumeColoringArray.png b/testing/baselines/TestVolumeColoringArray.png new file mode 100644 index 0000000000..cadd5b8dc5 --- /dev/null +++ b/testing/baselines/TestVolumeColoringArray.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4c0d14c52ee07aa5d72df760849ce9e14d7ff3322471ee847d856df8749d385 +size 8493 diff --git a/testing/baselines/TestVolumeNonScalars.png b/testing/baselines/TestVolumeNonScalars.png deleted file mode 100644 index 2c75bc3ec6..0000000000 --- a/testing/baselines/TestVolumeNonScalars.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:973771bb434dad7a720e3c7d77509684380f4e48f8c7ee4386082b1b7ed90e8c -size 82040 diff --git a/testing/recordings/TestInteractionInvalidComponent.log b/testing/recordings/TestInteractionInvalidComponent.log new file mode 100644 index 0000000000..1354832c8c --- /dev/null +++ b/testing/recordings/TestInteractionInvalidComponent.log @@ -0,0 +1,10 @@ +# StreamVersion 1.2 +ExposeEvent 0 599 0 0 0 0 0 +RenderEvent 0 599 0 0 0 0 0 +TimerEvent 0 599 0 0 0 0 0 +TimerEvent 0 599 0 0 0 0 0 +KeyPressEvent 291 357 0 104 1 h 0 +CharEvent 291 357 0 104 1 h 0 +TimerEvent 0 599 0 0 0 0 0 +KeyReleaseEvent 291 357 0 104 1 h 0 +TimerEvent 291 357 0 104 1 h 0 diff --git a/testing/recordings/TestInteractionVolumeAfterColoring.log b/testing/recordings/TestInteractionVolumeAfterColoring.log new file mode 100644 index 0000000000..67ea597153 --- /dev/null +++ b/testing/recordings/TestInteractionVolumeAfterColoring.log @@ -0,0 +1,28 @@ +# StreamVersion 1.2 +ExposeEvent 0 599 0 0 0 0 0 +RenderEvent 0 599 0 0 0 0 0 +TimerEvent 0 599 0 0 0 0 0 +KeyPressEvent 1394 -281 0 115 1 s 0 +CharEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyReleaseEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyPressEvent 1394 -281 0 115 1 s 0 +CharEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyReleaseEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyPressEvent 1394 -281 0 115 1 s 0 +CharEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyReleaseEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +TimerEvent 1394 -281 0 115 1 s 0 +KeyPressEvent 1394 -281 0 118 1 v 0 +CharEvent 1394 -281 0 118 1 v 0 +TimerEvent 1394 -281 0 118 1 v 0 +KeyReleaseEvent 1394 -281 0 118 1 v 0 +TimerEvent 1394 -281 0 118 1 v 0 +TimerEvent 1394 -281 0 118 1 v 0 diff --git a/testing/recordings/TestInteractionVolumeCycle.log b/testing/recordings/TestInteractionVolumeCycle.log new file mode 100644 index 0000000000..71cfe01cb8 --- /dev/null +++ b/testing/recordings/TestInteractionVolumeCycle.log @@ -0,0 +1,23 @@ +# StreamVersion 1.2 +ExposeEvent 0 599 0 0 0 0 0 +RenderEvent 0 599 0 0 0 0 0 +TimerEvent 0 599 0 0 0 0 0 +TimerEvent 0 599 0 0 0 0 0 +TimerEvent 363 259 0 0 0 0 0 +KeyPressEvent 363 259 0 118 1 v 0 +CharEvent 363 259 0 118 1 v 0 +TimerEvent 363 259 0 118 1 v 0 +KeyReleaseEvent 363 259 0 118 1 v 0 +TimerEvent 363 259 0 118 1 v 0 +TimerEvent 363 259 0 118 1 v 0 +KeyPressEvent 363 259 0 115 1 s 0 +CharEvent 363 259 0 115 1 s 0 +TimerEvent 363 259 0 115 1 s 0 +KeyReleaseEvent 363 259 0 115 1 s 0 +TimerEvent 363 259 0 115 1 s 0 +TimerEvent 363 259 0 115 1 s 0 +KeyPressEvent 363 259 0 115 1 s 0 +CharEvent 363 259 0 115 1 s 0 +TimerEvent 363 259 0 115 1 s 0 +KeyReleaseEvent 363 259 0 115 1 s 0 +TimerEvent 363 259 0 115 1 s 0 diff --git a/vtkext/private/module/CMakeLists.txt b/vtkext/private/module/CMakeLists.txt index 3e8de7fd99..26086ede7b 100644 --- a/vtkext/private/module/CMakeLists.txt +++ b/vtkext/private/module/CMakeLists.txt @@ -31,6 +31,7 @@ endforeach() set(classes F3DLog + F3DColoringInfoHandler vtkF3DCachedLUTTexture vtkF3DCachedSpecularTexture vtkF3DConsoleOutputWindow diff --git a/vtkext/private/module/F3DColoringInfoHandler.cxx b/vtkext/private/module/F3DColoringInfoHandler.cxx new file mode 100644 index 0000000000..d7966604f9 --- /dev/null +++ b/vtkext/private/module/F3DColoringInfoHandler.cxx @@ -0,0 +1,184 @@ +#include "F3DColoringInfoHandler.h" + +#include "F3DLog.h" + +#include +#include +#include +#include + +#include +#include + +//---------------------------------------------------------------------------- +void F3DColoringInfoHandler::ClearColoringInfo() +{ + this->PointDataColoringInfo.clear(); + this->CellDataColoringInfo.clear(); +} + +//---------------------------------------------------------------------------- +void F3DColoringInfoHandler::UpdateColoringInfo(vtkDataSet* dataset, bool useCellData) +{ + // XXX: This assumes importer do not import actors with an empty input + assert(dataset); + + // Recover all possible names + std::set arrayNames; + + vtkDataSetAttributes* attr = useCellData + ? static_cast(dataset->GetCellData()) + : static_cast(dataset->GetPointData()); + + for (int i = 0; i < attr->GetNumberOfArrays(); i++) + { + vtkDataArray* array = attr->GetArray(i); + if (array && array->GetName()) + { + arrayNames.insert(array->GetName()); + } + } + + auto& data = useCellData ? this->CellDataColoringInfo : this->PointDataColoringInfo; + + for (const std::string& arrayName : arrayNames) + { + // Recover/Create a coloring info + F3DColoringInfoHandler::ColoringInfo& info = data[arrayName]; + info.Name = arrayName; + + vtkDataArray* array = useCellData ? dataset->GetCellData()->GetArray(arrayName.c_str()) + : dataset->GetPointData()->GetArray(arrayName.c_str()); + if (array) + { + info.MaximumNumberOfComponents = + std::max(info.MaximumNumberOfComponents, array->GetNumberOfComponents()); + + // Set ranges + // XXX this does not take animation into account + std::array range; + array->GetRange(range.data(), -1); + info.MagnitudeRange[0] = std::min(info.MagnitudeRange[0], range[0]); + info.MagnitudeRange[1] = std::max(info.MagnitudeRange[1], range[1]); + + for (size_t i = 0; i < static_cast(array->GetNumberOfComponents()); i++) + { + array->GetRange(range.data(), static_cast(i)); + if (i < info.ComponentRanges.size()) + { + info.ComponentRanges[i][0] = std::min(info.ComponentRanges[i][0], range[0]); + info.ComponentRanges[i][1] = std::max(info.ComponentRanges[i][1], range[1]); + } + else + { + info.ComponentRanges.emplace_back(range); + } + } + + // Set component names + if (array->HasAComponentName()) + { + for (size_t i = 0; i < static_cast(array->GetNumberOfComponents()); i++) + { + const char* compName = array->GetComponentName(i); + if (i < info.ComponentNames.size()) + { + if (compName && info.ComponentNames[i] != std::string(compName)) + { + // set non-coherent component names to empty string + info.ComponentNames[i] = ""; + } + } + else + { + // Add components names to the back of the component names vector + info.ComponentNames.emplace_back(compName ? compName : ""); + } + } + } + } + } +} + +//---------------------------------------------------------------------------- +std::optional F3DColoringInfoHandler::SetCurrentColoring(bool enable, bool useCellData, const std::optional& arrayName, bool quiet) +{ + this->CurrentUsingCellData = useCellData; + auto& data = + this->CurrentUsingCellData ? this->CellDataColoringInfo : this->PointDataColoringInfo; + int nIndices = static_cast(data.size()); + + if (!enable) + { + // Not coloring + this->CurrentColoringIter.reset(); + } + else if (nIndices == 0) + { + // Trying to color but no array available + this->CurrentColoringIter.reset(); + + if (!quiet) + { + F3DLog::Print(F3DLog::Severity::Debug, "No array to color with\n"); + } + } + else if (!arrayName.has_value()) + { + // Coloring with first array + this->CurrentColoringIter = data.begin(); + } + else + { + // Coloring with named array + this->CurrentColoringIter = data.find(arrayName.value()); + if (this->CurrentColoringIter.value() == data.end()) + { + // Could not find named array + this->CurrentColoringIter.reset(); + if (!quiet) + { + F3DLog::Print(F3DLog::Severity::Warning, "Unknown scalar array: \"" + arrayName.value() + "\"\n"); + } + } + } + return this->GetCurrentColoringInfo(); +} + +//---------------------------------------------------------------------------- +std::optional F3DColoringInfoHandler::GetCurrentColoringInfo() const +{ + if (this->CurrentColoringIter.has_value()) + { + return this->CurrentColoringIter.value()->second; + } + return std::nullopt; +} + +//---------------------------------------------------------------------------- +void F3DColoringInfoHandler::CycleColoringArray(bool cycleToNonColoring) +{ + auto& data = + this->CurrentUsingCellData ? this->CellDataColoringInfo : this->PointDataColoringInfo; + if (!this->CurrentColoringIter.has_value()) + { + if(!data.empty()) + { + this->CurrentColoringIter = data.begin(); + } + } + else + { + if (++this->CurrentColoringIter.value() == data.end()) + { + if (cycleToNonColoring) + { + this->CurrentColoringIter.reset(); + } + else + { + this->CurrentColoringIter = data.begin(); + } + } + } +} diff --git a/vtkext/private/module/F3DColoringInfoHandler.h b/vtkext/private/module/F3DColoringInfoHandler.h new file mode 100644 index 0000000000..d21519f412 --- /dev/null +++ b/vtkext/private/module/F3DColoringInfoHandler.h @@ -0,0 +1,78 @@ +/** + * @class F3DColoringInfoHandler + * @brief A stateful handler to handle coloring info + */ +#ifndef F3DColoringInfoHandler_h +#define F3DColoringInfoHandler_h + +#include +#include +#include +#include +#include +#include + +class vtkDataSet; +class F3DColoringInfoHandler +{ +public: + /** + * A struct containing information about possible coloring + */ + struct ColoringInfo + { + std::string Name; + int MaximumNumberOfComponents = 0; + std::vector ComponentNames; + std::vector> ComponentRanges; + std::array MagnitudeRange = { std::numeric_limits::max(), + std::numeric_limits::min() }; + }; + + /** + * Update internal coloring maps using provided dataset + * useCellData control if point data or cell data should be updated + */ + void UpdateColoringInfo(vtkDataSet* dataset, bool useCellData); + + /** + * Clear all internal coloring maps + */ + void ClearColoringInfo(); + + /** + * Set the current coloring state + * @param enable: If coloring should be enabled or not + * @param useCellData: If cell data or point data should be used + * @param arrayName: An optional arrayName to color with + * @param quiet: If true, no log will be done by this method, even when failing to find an array to color with + * @return: current coloring info if any, unset optional otherwise + */ + std::optional SetCurrentColoring(bool enable, bool useCellData, const std::optional& arrayName, bool quiet); + + /** + * Get the current coloring state + * Return current coloring info if any, unset optional otherwise + */ + std::optional GetCurrentColoringInfo() const; + + /** + * Cycle the current coloring + * If not coloring, this will try to find an array to color with + * This does not change the cell/point data status + * @param cycleToNonColoring: Control whether to cycle to non coloring after reaching the last array or not + */ + void CycleColoringArray(bool cycleToNonColoring); + +private: + // Map of arrayName -> coloring info + using ColoringMap = std::map; + ColoringMap PointDataColoringInfo; + ColoringMap CellDataColoringInfo; + + // Current coloring state + bool CurrentUsingCellData = false; + std::optional CurrentColoringIter; +}; + +#endif diff --git a/vtkext/private/module/Testing/TestF3DMetaImporterMultiColoring.cxx b/vtkext/private/module/Testing/TestF3DMetaImporterMultiColoring.cxx index 97f220253f..d85a0ce138 100644 --- a/vtkext/private/module/Testing/TestF3DMetaImporterMultiColoring.cxx +++ b/vtkext/private/module/Testing/TestF3DMetaImporterMultiColoring.cxx @@ -41,13 +41,6 @@ int TestF3DMetaImporterMultiColoring(int argc, char* argv[]) return EXIT_FAILURE; } - if (importer->FindIndexForColoring(false, "") != -1) - { - std::cerr << "Unexpected FindIndexForColoring success" << std::endl; - return EXIT_FAILURE; - } - - // Read a vts and a vtu with same array names // but different component names and array ranges vtkNew readerVTU; @@ -71,54 +64,48 @@ int TestF3DMetaImporterMultiColoring(int argc, char* argv[]) importer->SetRenderWindow(window); importer->Update(); - if (importer->GetNumberOfIndexesForColoring(false) != 3) - { - std::cerr << "Importer provide unexpected number of indexes for coloring" << std::endl; - return EXIT_FAILURE; - } + // Test coloring handler + F3DColoringInfoHandler& coloringHandler = importer->GetColoringInfoHandler(); - int idx = importer->FindIndexForColoring(false, "Momentum"); - if (idx < 0) + auto info = coloringHandler.SetCurrentColoring(true, false, "Momentum", false); + if (!info.has_value()) { - std::cerr << "Importer unable to find an expected coloring array" << std::endl; + std::cerr << "Coloring handler unable to set coloring as expected" << std::endl; return EXIT_FAILURE; } - - vtkF3DMetaImporter::ColoringInfo info; - importer->GetInfoForColoring(false, idx, info); - if (info.Name != "Momentum") + if (info.value().Name != "Momentum") { - std::cerr << "Unexpected coloring name: " << info.Name << std::endl; + std::cerr << "Unexpected coloring name: " << info.value().Name << std::endl; return EXIT_FAILURE; } - if (info.MaximumNumberOfComponents != 3) + if (info.value().MaximumNumberOfComponents != 3) { std::cerr << "Unexpected coloring nComp" << std::endl; return EXIT_FAILURE; } - if (info.ComponentNames[0] != "LX Momentum") + if (info.value().ComponentNames[0] != "LX Momentum") { std::cerr << "Unexpected coloring component name 0" << std::endl; return EXIT_FAILURE; } - if (info.ComponentNames[1] != "LY Momentum_t") + if (info.value().ComponentNames[1] != "LY Momentum_t") { std::cerr << "Unexpected coloring component name 1" << std::endl; return EXIT_FAILURE; } - if (info.ComponentNames[2] != "") + if (info.value().ComponentNames[2] != "") { std::cerr << "Unexpected coloring component name 2" << std::endl; return EXIT_FAILURE; } - if (!vtkMathUtilities::FuzzyCompare(info.ComponentRanges[0][0], -5.49586, 1e-5) || - !vtkMathUtilities::FuzzyCompare(info.ComponentRanges[0][1], 5.79029, 1e-5)) + if (!vtkMathUtilities::FuzzyCompare(info.value().ComponentRanges[0][0], -5.49586, 1e-5) || + !vtkMathUtilities::FuzzyCompare(info.value().ComponentRanges[0][1], 5.79029, 1e-5)) { std::cerr << "Unexpected coloring component range" << std::endl; return EXIT_FAILURE; } - if (!vtkMathUtilities::FuzzyCompare(info.MagnitudeRange[0], 0., 1e-5) || - !vtkMathUtilities::FuzzyCompare(info.MagnitudeRange[1], 6.25568, 1e-5)) + if (!vtkMathUtilities::FuzzyCompare(info.value().MagnitudeRange[0], 0., 1e-5) || + !vtkMathUtilities::FuzzyCompare(info.value().MagnitudeRange[1], 6.25568, 1e-5)) { std::cerr << "Unexpected coloring magnitude range" << std::endl; return EXIT_FAILURE; diff --git a/vtkext/private/module/Testing/TestF3DRendererWithColoring.cxx b/vtkext/private/module/Testing/TestF3DRendererWithColoring.cxx index 6b1c58e67a..1f5ac4c12b 100644 --- a/vtkext/private/module/Testing/TestF3DRendererWithColoring.cxx +++ b/vtkext/private/module/Testing/TestF3DRendererWithColoring.cxx @@ -31,33 +31,35 @@ int TestF3DRendererWithColoring(int argc, char* argv[]) importer->Update(); // Check invalid array code path - renderer->SetColoring(true, false, "Invalid", 0); + renderer->SetEnableColoring(true); + renderer->SetArrayNameForColoring("Invalid"); renderer->SetUseVolume(false); renderer->UpdateActors(); - renderer->CycleScalars(vtkF3DRenderer::CycleType::COMPONENT); + renderer->CycleComponentForColoring(); renderer->SetUseVolume(true); renderer->UpdateActors(); - if (renderer->GetColoringArrayName() != "Density" || renderer->GetColoringComponent() != 0) + if (renderer->GetArrayNameForColoring() != "Invalid" || renderer->GetComponentForColoring() != -1) { std::cerr << "Unexpected coloring information with invalid array" << std::endl; return EXIT_FAILURE; } // Check invalid component code path - renderer->SetColoring(true, false, "Momentum", 5); + renderer->SetArrayNameForColoring("Momentum"); + renderer->SetComponentForColoring(5); renderer->UpdateActors(); renderer->SetUseVolume(true); renderer->UpdateActors(); - if (renderer->GetColoringArrayName() != "Momentum" || renderer->GetColoringComponent() != 5) + if (renderer->GetArrayNameForColoring() != "Momentum" || renderer->GetComponentForColoring() != 5) { std::cerr << "Unexpected coloring information with invalid component" << std::endl; return EXIT_FAILURE; } - renderer->CycleScalars(vtkF3DRenderer::CycleType::COMPONENT); - if (renderer->GetColoringArrayName() != "Momentum" || renderer->GetColoringComponent() != 1) + renderer->CycleComponentForColoring(); + if (renderer->GetArrayNameForColoring() != "Momentum" || renderer->GetComponentForColoring() != 1) { std::cerr << "Unexpected coloring information after cycling component" << std::endl; return EXIT_FAILURE; diff --git a/vtkext/private/module/vtkF3DMetaImporter.cxx b/vtkext/private/module/vtkF3DMetaImporter.cxx index 457db524e1..4cb32c6706 100644 --- a/vtkext/private/module/vtkF3DMetaImporter.cxx +++ b/vtkext/private/module/vtkF3DMetaImporter.cxx @@ -6,10 +6,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -19,125 +17,15 @@ #include #include #include -#include #include struct vtkF3DMetaImporter::Internals { - void ClearColoringInfo() - { - this->PointDataColoringInfo.clear(); - this->CellDataColoringInfo.clear(); - } - - void UpdateColoringInfo(vtkDataSet* dataset, bool useCellData) - { - // XXX: This assumes importer do not import actors with an empty input - assert(dataset); - - // Recover all possible names - std::set arrayNames; - - vtkDataSetAttributes* attr = useCellData - ? static_cast(dataset->GetCellData()) - : static_cast(dataset->GetPointData()); - - for (int i = 0; i < attr->GetNumberOfArrays(); i++) - { - vtkDataArray* array = attr->GetArray(i); - if (array && array->GetName()) - { - arrayNames.insert(array->GetName()); - } - } - - auto& data = useCellData ? this->CellDataColoringInfo : this->PointDataColoringInfo; - - for (const std::string& arrayName : arrayNames) - { - // Recover/Create a coloring info - vtkF3DMetaImporter::ColoringInfo& info = data[arrayName]; - info.Name = arrayName; - - vtkDataArray* array = useCellData ? dataset->GetCellData()->GetArray(arrayName.c_str()) - : dataset->GetPointData()->GetArray(arrayName.c_str()); - if (array) - { - info.MaximumNumberOfComponents = - std::max(info.MaximumNumberOfComponents, array->GetNumberOfComponents()); - - // Set ranges - // XXX this does not take animation into account - std::array range; - array->GetRange(range.data(), -1); - info.MagnitudeRange[0] = std::min(info.MagnitudeRange[0], range[0]); - info.MagnitudeRange[1] = std::max(info.MagnitudeRange[1], range[1]); - - for (size_t i = 0; i < static_cast(array->GetNumberOfComponents()); i++) - { - array->GetRange(range.data(), static_cast(i)); - if (i < info.ComponentRanges.size()) - { - info.ComponentRanges[i][0] = std::min(info.ComponentRanges[i][0], range[0]); - info.ComponentRanges[i][1] = std::max(info.ComponentRanges[i][1], range[1]); - } - else - { - info.ComponentRanges.emplace_back(range); - } - } - - // Set component names - if (array->HasAComponentName()) - { - for (size_t i = 0; i < static_cast(array->GetNumberOfComponents()); i++) - { - const char* compName = array->GetComponentName(i); - if (i < info.ComponentNames.size()) - { - if (compName && info.ComponentNames[i] != std::string(compName)) - { - // set non-coherent component names to empty string - info.ComponentNames[i] = ""; - } - } - else - { - // Add components names to the back of the component names vector - info.ComponentNames.emplace_back(compName ? compName : ""); - } - } - } - } - } - } - - void FinalizeColoringInfo(bool useCellData) - { - auto& names = useCellData ? this->CellDataArrayNames : this->PointDataArrayNames; - names.clear(); - - auto& data = useCellData ? this->CellDataColoringInfo : this->PointDataColoringInfo; - int index = 0; - for (auto& [name, info] : data) - { - info.Index = index; - names.emplace_back(name); - index++; - } - } - // Actors related vectors std::vector ColoringActorsAndMappers; std::vector PointSpritesActorsAndMappers; std::vector VolumePropsAndMappers; - // Map of arrayName -> coloring info - std::map PointDataColoringInfo; - std::map CellDataColoringInfo; - std::vector PointDataArrayNames; - std::vector CellDataArrayNames; - struct ImporterPair { vtkSmartPointer Importer; @@ -148,6 +36,8 @@ struct vtkF3DMetaImporter::Internals vtkBoundingBox GeometryBoundingBox; bool ColoringInfoUpdated = false; + F3DColoringInfoHandler ColoringInfoHandler; + #if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 3, 20240707) std::map> ActorsForImporterMap; #endif @@ -178,7 +68,7 @@ void vtkF3DMetaImporter::Clear() this->Pimpl->ColoringActorsAndMappers.clear(); this->Pimpl->PointSpritesActorsAndMappers.clear(); this->Pimpl->VolumePropsAndMappers.clear(); - this->Pimpl->ClearColoringInfo(); + this->Pimpl->ColoringInfoHandler.ClearColoringInfo(); this->Modified(); } @@ -217,61 +107,6 @@ const vtkBoundingBox& vtkF3DMetaImporter::GetGeometryBoundingBox() return this->Pimpl->GeometryBoundingBox; } -//---------------------------------------------------------------------------- -bool vtkF3DMetaImporter::GetInfoForColoring( - bool useCellData, int index, vtkF3DMetaImporter::ColoringInfo& info) -{ - if (!this->Pimpl->ColoringInfoUpdated) - { - this->UpdateInfoForColoring(); - } - - auto& data = - useCellData ? this->Pimpl->CellDataColoringInfo : this->Pimpl->PointDataColoringInfo; - auto& names = - useCellData ? this->Pimpl->CellDataArrayNames : this->Pimpl->PointDataArrayNames; - - if (index < 0 || index >= static_cast(data.size())) - { - return false; - } - - info = data[names[index]]; - return true; -} - -//---------------------------------------------------------------------------- -int vtkF3DMetaImporter::GetNumberOfIndexesForColoring(bool useCellData) -{ - if (!this->Pimpl->ColoringInfoUpdated) - { - this->UpdateInfoForColoring(); - } - - auto& data = - useCellData ? this->Pimpl->CellDataColoringInfo : this->Pimpl->PointDataColoringInfo; - return static_cast(data.size()); -} - -//---------------------------------------------------------------------------- -int vtkF3DMetaImporter::FindIndexForColoring(bool useCellData, const std::string& arrayName) -{ - if (!this->Pimpl->ColoringInfoUpdated) - { - this->UpdateInfoForColoring(); - } - - auto& data = - useCellData ? this->Pimpl->CellDataColoringInfo : this->Pimpl->PointDataColoringInfo; - - auto it = data.find(arrayName); - if (it != data.end()) - { - return it->second.Index; - } - return -1; -} - //---------------------------------------------------------------------------- const std::vector& vtkF3DMetaImporter::GetColoringActorsAndMappers() @@ -672,13 +507,10 @@ void vtkF3DMetaImporter::UpdateInfoForColoring() datasetForColoring = genericImporter->GetImportedPoints(); } } - this->Pimpl->UpdateColoringInfo(datasetForColoring, false); - this->Pimpl->UpdateColoringInfo(datasetForColoring, true); + this->Pimpl->ColoringInfoHandler.UpdateColoringInfo(datasetForColoring, false); + this->Pimpl->ColoringInfoHandler.UpdateColoringInfo(datasetForColoring, true); } } - - this->Pimpl->FinalizeColoringInfo(false); - this->Pimpl->FinalizeColoringInfo(true); this->Pimpl->ColoringInfoUpdated = true; } @@ -715,3 +547,14 @@ std::string vtkF3DMetaImporter::GetMetaDataDescription() const description += std::to_string(nCells); return description; } + +//---------------------------------------------------------------------------- +F3DColoringInfoHandler& vtkF3DMetaImporter::GetColoringInfoHandler() +{ + if (!this->Pimpl->ColoringInfoUpdated) + { + this->UpdateInfoForColoring(); + } + + return this->Pimpl->ColoringInfoHandler; +} diff --git a/vtkext/private/module/vtkF3DMetaImporter.h b/vtkext/private/module/vtkF3DMetaImporter.h index 37b2ee4999..7a9c1850a3 100644 --- a/vtkext/private/module/vtkF3DMetaImporter.h +++ b/vtkext/private/module/vtkF3DMetaImporter.h @@ -7,6 +7,7 @@ #define vtkF3DMetaImporter_h #include "vtkF3DImporter.h" +#include "F3DColoringInfoHandler.h" #include #include @@ -20,8 +21,6 @@ #include #endif -#include -#include #include #include #include @@ -77,20 +76,6 @@ class vtkF3DMetaImporter : public vtkF3DImporter }; ///@} - /** - * A struct containing information about possible coloring - */ - struct ColoringInfo - { - std::string Name; - int MaximumNumberOfComponents = 0; - std::vector ComponentNames; - std::vector> ComponentRanges; - std::array MagnitudeRange = { std::numeric_limits::max(), - std::numeric_limits::min() }; - int Index = -1; - }; - /** * Clear all importers and internal structures */ @@ -112,23 +97,8 @@ class vtkF3DMetaImporter : public vtkF3DImporter */ std::string GetMetaDataDescription() const; - /** - * Recover information about coloring by index - * Should be called after actors have been imported - */ - bool GetInfoForColoring(bool useCellData, int index, ColoringInfo& info); - /** - * Get the maximum index possible for coloring - * Should be called after actors have been imported - */ - int GetNumberOfIndexesForColoring(bool useCellData); - - /** - * Find an index for coloring corresponding to provided arrayName if available - * Should be called after actors have been imported - */ - int FindIndexForColoring(bool useCellData, const std::string& arrayName); + F3DColoringInfoHandler& GetColoringInfoHandler(); ///@{ /** diff --git a/vtkext/private/module/vtkF3DRenderer.cxx b/vtkext/private/module/vtkF3DRenderer.cxx index 6dcf884f91..06fa03ab88 100644 --- a/vtkext/private/module/vtkF3DRenderer.cxx +++ b/vtkext/private/module/vtkF3DRenderer.cxx @@ -2,6 +2,7 @@ #include "F3DDefaultHDRI.h" #include "F3DLog.h" +#include "F3DColoringInfoHandler.h" #include "vtkF3DCachedLUTTexture.h" #include "vtkF3DCachedSpecularTexture.h" #include "vtkF3DConfigure.h" @@ -281,9 +282,6 @@ void vtkF3DRenderer::Initialize() this->AnimationNameInfo = ""; this->GridInfo = ""; - this->ArrayIndexForColoring = -1; - this->ComponentForColoring = -1; - this->AddActor2D(this->ScalarBarActor); this->ScalarBarActor->VisibilityOff(); @@ -483,27 +481,21 @@ void vtkF3DRenderer::ShowAxis(bool show) this->AxisWidget = nullptr; if (show) { - if (this->RenderWindow->GetInteractor()) - { - vtkNew axes; + assert(this->RenderWindow->GetInteractor()); + vtkNew axes; #if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 2, 20220907) - this->AxisWidget = vtkSmartPointer::New(); + this->AxisWidget = vtkSmartPointer::New(); #else - this->AxisWidget = vtkSmartPointer::New(); + this->AxisWidget = vtkSmartPointer::New(); #endif - this->AxisWidget->SetOrientationMarker(axes); - this->AxisWidget->SetInteractor(this->RenderWindow->GetInteractor()); - this->AxisWidget->SetViewport(0.85, 0.0, 1.0, 0.15); - this->AxisWidget->On(); + this->AxisWidget->SetOrientationMarker(axes); + this->AxisWidget->SetInteractor(this->RenderWindow->GetInteractor()); + this->AxisWidget->SetViewport(0.85, 0.0, 1.0, 0.15); + this->AxisWidget->On(); #if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 2, 20220907) - this->AxisWidget->InteractiveOff(); + this->AxisWidget->InteractiveOff(); #endif - this->AxisWidget->SetKeyPressActivation(false); - } - else - { - F3DLog::Print(F3DLog::Severity::Error, "Axis widget cannot be shown without an interactor"); - } + this->AxisWidget->SetKeyPressActivation(false); } this->AxisVisible = show; @@ -1369,11 +1361,51 @@ void vtkF3DRenderer::ShowCheatSheet(bool show) //---------------------------------------------------------------------------- void vtkF3DRenderer::ConfigureCheatSheet() { + assert(this->Importer); if (this->CheatSheetVisible) { + auto info = this->Importer->GetColoringInfoHandler().GetCurrentColoringInfo(); std::stringstream cheatSheetText; cheatSheetText << "\n"; - this->FillCheatSheetHotkeys(cheatSheetText); + cheatSheetText << " C: Cell scalars coloring [" << (this->UseCellColoring ? "ON" : "OFF") + << "]\n"; + cheatSheetText << " S: Scalars coloring [" + << (info.has_value() ? vtkF3DRenderer::ShortName(info.value().Name, 19) + (this->EnableColoring ? "" : "(forced)") : "OFF") << "]\n"; + cheatSheetText << " Y: Coloring component [" + << vtkF3DRenderer::ComponentToString(this->ComponentForColoring) + << "]\n"; + cheatSheetText << " B: Scalar bar " << (this->ScalarBarVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " V: Volume representation " << (this->UseVolume ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " I: Inverse volume opacity " + << (this->UseInverseOpacityFunction ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " O: Point sprites " << (this->UsePointSprites ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " W: Cycle animation [" + << vtkF3DRenderer::ShortName(this->AnimationNameInfo, 22) << "]\n"; + cheatSheetText << " P: Translucency support " << (this->UseDepthPeelingPass ? "[ON]" : "[OFF]") + << "\n"; + cheatSheetText << " Q: Ambient occlusion " << (this->UseSSAOPass ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " A: Anti-aliasing " << (this->UseFXAAPass ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " T: Tone mapping " << (this->UseToneMappingPass ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " E: Edge visibility " << (this->EdgeVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " X: Axis " << (this->AxisVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " G: Grid " << (this->GridVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " N: File name " << (this->FilenameVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " M: Metadata " << (this->MetaDataVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " Z: FPS Timer " << (this->TimerVisible ? "[ON]" : "[OFF]") << "\n"; +#if F3D_MODULE_RAYTRACING + cheatSheetText << " R: Raytracing " << (this->UseRaytracing ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " D: Denoiser " << (this->UseRaytracingDenoiser ? "[ON]" : "[OFF]") << "\n"; +#endif + cheatSheetText << " U: Blur background " << (this->UseBlurBackground ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " K: Trackball interaction " << (this->UseTrackball ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " F: HDRI ambient lighting " + << (this->GetUseImageBasedLighting() ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText << " J: HDRI skybox " << (this->HDRISkyboxVisible ? "[ON]" : "[OFF]") << "\n"; + cheatSheetText.precision(2); + cheatSheetText << std::fixed; + cheatSheetText << " L: Light (increase, shift+L: decrease) [" << this->LightIntensity << "]" + << " \n"; + cheatSheetText << "\n H : Cheat sheet \n"; cheatSheetText << " ? : Print scene descr to terminal\n"; cheatSheetText << " ESC : Quit \n"; @@ -1386,7 +1418,7 @@ void vtkF3DRenderer::ConfigureCheatSheet() cheatSheetText << " 3: Right View camera\n"; cheatSheetText << " 4: Roll the camera left by 90 degrees\n"; cheatSheetText << " 5: Toggle Orthographic Projection " - << (this->UseOrthographicProjection ? "[ON]" : "[OFF]") << "\n"; + << (this->UseOrthographicProjection ? "[ON]" : "[OFF]") << "\n"; cheatSheetText << " 6: Roll the camera right by 90 degrees\n"; cheatSheetText << " 7: Top View camera\n"; cheatSheetText << " 9: Isometric View camera\n"; @@ -1424,56 +1456,6 @@ void vtkF3DRenderer::ShowHDRISkybox(bool show) } } -//---------------------------------------------------------------------------- -void vtkF3DRenderer::FillCheatSheetHotkeys(std::stringstream& cheatSheetText) -{ - assert(this->Importer); - - vtkF3DMetaImporter::ColoringInfo info; - bool hasColoring = - this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info); - - cheatSheetText << " C: Cell scalars coloring [" << (this->UseCellColoring ? "ON" : "OFF") - << "]\n"; - cheatSheetText << " S: Scalars coloring [" - << (hasColoring ? vtkF3DRenderer::ShortName(info.Name, 19) : "OFF") << "]\n"; - cheatSheetText << " Y: Coloring component [" - << vtkF3DRenderer::ComponentToString(this->ComponentForColoring) - << "]\n"; - cheatSheetText << " B: Scalar bar " << (this->ScalarBarVisible ? "[ON]" : "[OFF]") << "\n"; - - cheatSheetText << " V: Volume representation " << (this->UseVolume ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " I: Inverse volume opacity " - << (this->UseInverseOpacityFunction ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " O: Point sprites " << (this->UsePointSprites ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " W: Cycle animation [" - << vtkF3DRenderer::ShortName(this->AnimationNameInfo, 22) << "]\n"; - cheatSheetText << " P: Translucency support " << (this->UseDepthPeelingPass ? "[ON]" : "[OFF]") - << "\n"; - cheatSheetText << " Q: Ambient occlusion " << (this->UseSSAOPass ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " A: Anti-aliasing " << (this->UseFXAAPass ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " T: Tone mapping " << (this->UseToneMappingPass ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " E: Edge visibility " << (this->EdgeVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " X: Axis " << (this->AxisVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " G: Grid " << (this->GridVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " N: File name " << (this->FilenameVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " M: Metadata " << (this->MetaDataVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " Z: FPS Timer " << (this->TimerVisible ? "[ON]" : "[OFF]") << "\n"; -#if F3D_MODULE_RAYTRACING - cheatSheetText << " R: Raytracing " << (this->UseRaytracing ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " D: Denoiser " << (this->UseRaytracingDenoiser ? "[ON]" : "[OFF]") << "\n"; -#endif - cheatSheetText << " U: Blur background " << (this->UseBlurBackground ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " K: Trackball interaction " << (this->UseTrackball ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " F: HDRI ambient lighting " - << (this->GetUseImageBasedLighting() ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText << " J: HDRI skybox " << (this->HDRISkyboxVisible ? "[ON]" : "[OFF]") << "\n"; - cheatSheetText.precision(2); - cheatSheetText << std::fixed; - cheatSheetText << " L: Light (increase, shift+L: decrease) [" << this->LightIntensity << "]" - << " \n"; -} - //---------------------------------------------------------------------------- void vtkF3DRenderer::ShowEdge(const std::optional& show) { @@ -1916,7 +1898,7 @@ void vtkF3DRenderer::ConfigureActorsProperties() emissiveFactor = this->EmissiveFactor.value().data(); } } - + bool setBackfaceCulling = false; bool backfaceCulling = true; if (this->BackfaceType.has_value()) @@ -2231,154 +2213,68 @@ void vtkF3DRenderer::SetColormap(const std::vector& colormap) } //---------------------------------------------------------------------------- -void vtkF3DRenderer::CycleScalars(CycleType type) +void vtkF3DRenderer::SetEnableColoring(bool enable) { - switch (type) + if (enable != this->EnableColoring) { - case (CycleType::NONE): - return; - break; - case (CycleType::FIELD): - this->CycleFieldForColoring(); - break; - case (CycleType::ARRAY_INDEX): - this->CycleArrayIndexForColoring(); - break; - case (CycleType::COMPONENT): - this->CycleComponentForColoring(); - break; - default: - break; + this->EnableColoring = enable; + this->CheatSheetConfigured = false; + this->ColoringConfigured = false; } - - // Check attributes are valid and cycle recursively if needed - this->CycleScalars(this->CheckColoring()); - - this->ColorTransferFunctionConfigured = false; - this->ColoringMappersConfigured = false; - this->PointSpritesMappersConfigured = false; - this->VolumePropsAndMappersConfigured = false; - this->ScalarBarActorConfigured = false; - this->CheatSheetConfigured = false; - this->ColoringConfigured = false; } //---------------------------------------------------------------------------- -vtkF3DRenderer::CycleType vtkF3DRenderer::CheckColoring() +void vtkF3DRenderer::SetUseCellColoring(bool useCell) { - assert(this->Importer); - - // Never force change of anything if we are currently not coloring - if (this->ArrayIndexForColoring < 0) - { - return CycleType::NONE; - } - - // Never force change of CellData/PointData coloring on the user - if (this->Importer->GetNumberOfIndexesForColoring(this->UseCellColoring) == 0) - { - return CycleType::NONE; - } - - // Suggest to change the array index only if current index is not valid - vtkF3DMetaImporter::ColoringInfo info; - if (!this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info)) + if (useCell != this->UseCellColoring) { - return CycleType::ARRAY_INDEX; - } - - // Suggest to change the component if current component is invalid - if (this->ComponentForColoring >= info.MaximumNumberOfComponents) - { - return CycleType::COMPONENT; + this->UseCellColoring = useCell; + this->ColorTransferFunctionConfigured = false; + this->ColoringMappersConfigured = false; + this->PointSpritesMappersConfigured = false; + this->VolumePropsAndMappersConfigured = false; + this->ScalarBarActorConfigured = false; + this->CheatSheetConfigured = false; + this->ColoringConfigured = false; } - - return CycleType::NONE; } //---------------------------------------------------------------------------- -void vtkF3DRenderer::SetColoring(bool enable, - bool useCellData, const std::optional& arrayName, int component) +void vtkF3DRenderer::SetArrayNameForColoring(const std::optional& arrayName) { - assert(this->Importer); - - // XXX This should be reworked to avoid handling multiple information in one parameters - // while still being future-proof and flexible enough. - if (enable != (this->ArrayIndexForColoring >= 0) - || useCellData != this->UseCellColoring - || component != this->ComponentForColoring - || arrayName != this->GetColoringArrayName()) + if (arrayName != this->ArrayNameForColoring) { - this->UseCellColoring = useCellData; - this->ComponentForColoring = component; - - int nIndexes = this->Importer->GetNumberOfIndexesForColoring(this->UseCellColoring); - if (!enable) - { - // Not coloring - this->ArrayIndexForColoring = -1; - } - else if (nIndexes == 0) - { - // Trying to color but no array available - F3DLog::Print(F3DLog::Severity::Debug, "No array to color with"); - this->ArrayIndexForColoring = -1; - } - else if (!arrayName.has_value()) - { - // Coloring with first array - this->ArrayIndexForColoring = 0; - } - else - { - // Coloring with named array - this->ArrayIndexForColoring = this->Importer->FindIndexForColoring(useCellData, arrayName.value()); - if (this->ArrayIndexForColoring == -1) - { - // Could not find named array - F3DLog::Print(F3DLog::Severity::Warning, "Unknown scalar array: \"" + arrayName.value() + "\"\n"); - } - } - + this->ArrayNameForColoring = arrayName; this->ColorTransferFunctionConfigured = false; this->ColoringMappersConfigured = false; this->PointSpritesMappersConfigured = false; this->VolumePropsAndMappersConfigured = false; this->ScalarBarActorConfigured = false; + this->CheatSheetConfigured = false; this->ColoringConfigured = false; } } //---------------------------------------------------------------------------- -bool vtkF3DRenderer::GetColoringEnabled() +std::optional vtkF3DRenderer::GetArrayNameForColoring() { - return this->ArrayIndexForColoring >= 0; + return this->ArrayNameForColoring; } //---------------------------------------------------------------------------- -bool vtkF3DRenderer::GetColoringUseCell() +void vtkF3DRenderer::SetComponentForColoring(int component) { - return this->UseCellColoring; -} - -//---------------------------------------------------------------------------- -std::optional vtkF3DRenderer::GetColoringArrayName() -{ - assert(this->Importer); - - std::optional arrayName; - vtkF3DMetaImporter::ColoringInfo info; - if (this->Importer && this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info)) + if (component != this->ComponentForColoring) { - arrayName = info.Name; + this->ComponentForColoring = component; + this->ColorTransferFunctionConfigured = false; + this->ColoringMappersConfigured = false; + this->PointSpritesMappersConfigured = false; + this->VolumePropsAndMappersConfigured = false; + this->ScalarBarActorConfigured = false; + this->CheatSheetConfigured = false; + this->ColoringConfigured = false; } - return arrayName; -} - -//---------------------------------------------------------------------------- -int vtkF3DRenderer::GetColoringComponent() -{ - return this->ComponentForColoring; } //---------------------------------------------------------------------------- @@ -2386,23 +2282,14 @@ void vtkF3DRenderer::ConfigureColoring() { assert(this->Importer); - // Recover coloring information - vtkF3DMetaImporter::ColoringInfo info; - bool hasColoring = - this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info); - - bool volumeVisible = !this->UseRaytracing && this->UseVolume; - if (!hasColoring && volumeVisible) - { - // When showing volume, always try to find an array to color with - this->CycleScalars(vtkF3DRenderer::CycleType::ARRAY_INDEX); - hasColoring = - this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info); - } - + // Recover coloring information and update handler + bool enableColoring = this->EnableColoring || (!this->UseRaytracing && this->UseVolume); + F3DColoringInfoHandler& coloringHandler = this->Importer->GetColoringInfoHandler(); + auto info = coloringHandler.SetCurrentColoring(enableColoring, this->UseCellColoring, this->ArrayNameForColoring, false); + bool hasColoring = info.has_value(); if (hasColoring && !this->ColorTransferFunctionConfigured) { - this->ConfigureRangeAndCTFForColoring(info); + this->ConfigureRangeAndCTFForColoring(info.value()); this->ColorTransferFunctionConfigured = true; } @@ -2419,7 +2306,7 @@ void vtkF3DRenderer::ConfigureColoring() visible = mapper->GetScalarVisibility(); if (!this->ColoringMappersConfigured) { - visible = vtkF3DRenderer::ConfigureMapperForColoring(mapper, info.Name, + visible = vtkF3DRenderer::ConfigureMapperForColoring(mapper, info.value().Name, this->ComponentForColoring, this->ColorTransferFunction, this->ColorRange, this->UseCellColoring); } @@ -2449,7 +2336,7 @@ void vtkF3DRenderer::ConfigureColoring() { if (!this->PointSpritesMappersConfigured) { - vtkF3DRenderer::ConfigureMapperForColoring(mapper, info.Name, + vtkF3DRenderer::ConfigureMapperForColoring(mapper, info.value().Name, this->ComponentForColoring, this->ColorTransferFunction, this->ColorRange, this->UseCellColoring); } @@ -2463,6 +2350,7 @@ void vtkF3DRenderer::ConfigureColoring() } // Handle Volume prop + bool volumeVisible = !this->UseRaytracing && this->UseVolume; const auto& volPropsAndMappers = this->Importer->GetVolumePropsAndMappers(); for (const auto& [prop, mapper] : volPropsAndMappers) { @@ -2480,13 +2368,13 @@ void vtkF3DRenderer::ConfigureColoring() if (!this->VolumePropsAndMappersConfigured) { visible = vtkF3DRenderer::ConfigureVolumeForColoring(mapper, - prop, info.Name, this->ComponentForColoring, + prop, info.value().Name, this->ComponentForColoring, this->ColorTransferFunction, this->ColorRange, this->UseCellColoring, this->UseInverseOpacityFunction); if (!visible) { F3DLog::Print( - F3DLog::Severity::Warning, "Cannot find the array \"" + info.Name + "\" to display volume with"); + F3DLog::Severity::Warning, "Cannot find the array \"" + info.value().Name + "\" to display volume with"); } } } @@ -2509,7 +2397,7 @@ void vtkF3DRenderer::ConfigureColoring() if (barVisible && !this->ScalarBarActorConfigured) { vtkF3DRenderer::ConfigureScalarBarActorForColoring( - this->ScalarBarActor, info.Name, this->ComponentForColoring, this->ColorTransferFunction); + this->ScalarBarActor, info.value().Name, this->ComponentForColoring, this->ColorTransferFunction); this->ScalarBarActorConfigured = true; } @@ -2523,11 +2411,11 @@ std::string vtkF3DRenderer::GetColoringDescription() assert(this->Importer); std::stringstream stream; - vtkF3DMetaImporter::ColoringInfo info; - if (this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info)) + auto info = this->Importer->GetColoringInfoHandler().GetCurrentColoringInfo(); + if (info.has_value()) { stream << "Coloring using " << (this->UseCellColoring ? "cell" : "point") << " array named " - << info.Name << ", " + << info.value().Name << (this->EnableColoring ? ", " : " (forced), ") << vtkF3DRenderer::ComponentToString(this->ComponentForColoring) << "\n"; } else @@ -2657,7 +2545,7 @@ void vtkF3DRenderer::ConfigureScalarBarActorForColoring( //---------------------------------------------------------------------------- void vtkF3DRenderer::ConfigureRangeAndCTFForColoring( - const vtkF3DMetaImporter::ColoringInfo& info) + const F3DColoringInfoHandler::ColoringInfo& info) { if (this->ComponentForColoring == -2) { @@ -2739,30 +2627,39 @@ void vtkF3DRenderer::ConfigureRangeAndCTFForColoring( //---------------------------------------------------------------------------- void vtkF3DRenderer::CycleFieldForColoring() { - // A generic approach will be better when adding categorical field data coloring - this->UseCellColoring = !this->UseCellColoring; + // XXX: A generic approach will be better when adding categorical field data coloring + this->SetUseCellColoring(!this->UseCellColoring); + bool enableColoring = this->EnableColoring || (!this->UseRaytracing && this->UseVolume); + F3DColoringInfoHandler& coloringHandler = this->Importer->GetColoringInfoHandler(); + auto info = coloringHandler.SetCurrentColoring(enableColoring, this->UseCellColoring, this->ArrayNameForColoring, true); + if (!info.has_value()) + { + // Cycle array if the current one is not valid + this->CycleArrayForColoring(); + } } //---------------------------------------------------------------------------- -void vtkF3DRenderer::CycleArrayIndexForColoring() +void vtkF3DRenderer::CycleArrayForColoring() { assert(this->Importer); + this->Importer->GetColoringInfoHandler().CycleColoringArray(!this->UseVolume); //TODO check this cond + auto info = this->Importer->GetColoringInfoHandler().GetCurrentColoringInfo(); + bool enable = info.has_value(); - int nIndex = this->Importer->GetNumberOfIndexesForColoring(this->UseCellColoring); - if (nIndex <= 0) + this->SetEnableColoring(enable); + if (this->EnableColoring) { - return; - } - - if (this->UseVolume) - { - this->ArrayIndexForColoring = (this->ArrayIndexForColoring + 1) % nIndex; + this->SetArrayNameForColoring(info.value().Name); + if (this->ComponentForColoring >= info.value().MaximumNumberOfComponents) + { + // Cycle component if the current one is not valid + this->CycleComponentForColoring(); + } } else { - // Cycle through arrays looping back to -1 - // -1 0 1 2 -1 0 1 2 ... - this->ArrayIndexForColoring = (this->ArrayIndexForColoring + 2) % (nIndex + 1) - 1; + this->SetArrayNameForColoring(std::nullopt); } } @@ -2771,15 +2668,15 @@ void vtkF3DRenderer::CycleComponentForColoring() { assert(this->Importer); - vtkF3DMetaImporter::ColoringInfo info; - if (!this->Importer->GetInfoForColoring(this->UseCellColoring, this->ArrayIndexForColoring, info)) + auto info = this->Importer->GetColoringInfoHandler().GetCurrentColoringInfo(); + if (!info.has_value()) { return; } // -2 -1 0 1 2 3 4 - this->ComponentForColoring = - (this->ComponentForColoring + 3) % (info.MaximumNumberOfComponents + 2) - 2; + this->SetComponentForColoring( + (this->ComponentForColoring + 3) % (info.value().MaximumNumberOfComponents + 2) - 2); } //---------------------------------------------------------------------------- @@ -2797,21 +2694,20 @@ std::string vtkF3DRenderer::ComponentToString(int component) } else { - vtkF3DMetaImporter::ColoringInfo info; - if (!this->Importer->GetInfoForColoring( - this->UseCellColoring, this->ArrayIndexForColoring, info)) + auto info = this->Importer->GetColoringInfoHandler().GetCurrentColoringInfo(); + if (!info.has_value()) { return ""; } - if (component >= info.MaximumNumberOfComponents) + if (component >= info.value().MaximumNumberOfComponents) { return ""; } std::string componentName; - if (component < static_cast(info.ComponentNames.size())) + if (component < static_cast(info.value().ComponentNames.size())) { - componentName = info.ComponentNames[component]; + componentName = info.value().ComponentNames[component]; } if (componentName.empty()) { diff --git a/vtkext/private/module/vtkF3DRenderer.h b/vtkext/private/module/vtkF3DRenderer.h index 973862a47d..b84e2e1c5b 100644 --- a/vtkext/private/module/vtkF3DRenderer.h +++ b/vtkext/private/module/vtkF3DRenderer.h @@ -282,40 +282,41 @@ class vtkF3DRenderer : public vtkOpenGLRenderer */ void SetColormap(const std::vector& colormap); - enum class CycleType - { - NONE, - FIELD, - ARRAY_INDEX, - COMPONENT - }; - - /** - * Cycle the shown scalars according to the cycle type - */ - void CycleScalars(CycleType type); - /** * Set the meta importer to recover coloring information from */ void SetImporter(vtkF3DMetaImporter* importer); + ///@{ /** - * Set coloring information. - * This method will try to find the corresponding array in the coloring attributes and will - * position ArrayIndexForColoring and DataForColoring accordingly. + * Set/Get if coloring is enabled */ - void SetColoring(bool enable, bool useCellData, const std::optional& arrayName, int component); + void SetEnableColoring(bool enable); + vtkGetMacro(EnableColoring, bool); + ///@} ///@{ /** - * Get current coloring information, - * Useful after using Cycle methods + * Set/Get if using point or cell data coloring + */ + void SetUseCellColoring(bool useCell); + vtkGetMacro(UseCellColoring, bool); + ///@} + + ///@{ + /** + * Set/Get the name of the array to use for coloring */ - bool GetColoringEnabled(); - bool GetColoringUseCell(); - std::optional GetColoringArrayName(); - int GetColoringComponent(); + void SetArrayNameForColoring(const std::optional& arrayName); + std::optional GetArrayNameForColoring(); + ///@} + + ///@{ + /** + * Set/Get the name of the component to use for coloring + */ + void SetComponentForColoring(int component); + vtkGetMacro(ComponentForColoring, int); ///@} /** @@ -323,6 +324,26 @@ class vtkF3DRenderer : public vtkOpenGLRenderer */ virtual std::string GetColoringDescription(); + /** + * Switch between point data and cell data coloring, actually setting UseCellColoring member. + * This can trigger CycleArrayForColoring if current array is not valid. + */ + void CycleFieldForColoring(); + + /** + * Cycle the current array for coloring, actually setting EnableColoring and ArrayNameForColoring members. + * This loops back to not coloring if volume is not enabled. + * This can trigger CycleComponentForColoring if current component is not valid. + */ + void CycleArrayForColoring(); + + /** + * Cycle the component in used for rendering + * looping back to direct scalars + */ + void CycleComponentForColoring(); + + private: vtkF3DRenderer(); ~vtkF3DRenderer() override; @@ -369,7 +390,7 @@ class vtkF3DRenderer : public vtkOpenGLRenderer void ConfigureActorsProperties(); /** - * Configure the cheatsheet text and mark it for rendering + * Configure the cheatsheet text and hotkeys and mark it for rendering */ void ConfigureCheatSheet(); @@ -383,11 +404,6 @@ class vtkF3DRenderer : public vtkOpenGLRenderer */ void ConfigureRenderPasses(); - /** - * Add all hotkeys options to the cheatsheet. - */ - void FillCheatSheetHotkeys(std::stringstream& sheet); - /** * Generate a padded metadata description * using the internal importer @@ -434,30 +450,7 @@ class vtkF3DRenderer : public vtkOpenGLRenderer * Configure internal range and color transfer function according to provided * coloring info */ - void ConfigureRangeAndCTFForColoring(const vtkF3DMetaImporter::ColoringInfo& info); - - /** - * Switch between point data and cell data coloring - */ - void CycleFieldForColoring(); - - /** - * Increment the array index or loop it back - * When not using volume, it will loop back - * to not coloring - */ - void CycleArrayIndexForColoring(); - - /** - * Cycle the component in used for rendering - * looping back to direct scalars - */ - void CycleComponentForColoring(); - - /** - * Check coloring is currently valid and return a cycle type to perform if not - */ - CycleType CheckColoring(); + void ConfigureRangeAndCTFForColoring(const F3DColoringInfoHandler::ColoringInfo& info); /** * Convert a component index into a string @@ -466,7 +459,6 @@ class vtkF3DRenderer : public vtkOpenGLRenderer */ std::string ComponentToString(int component); - vtkSmartPointer AxisWidget; vtkNew FilenameActor; @@ -580,9 +572,10 @@ class vtkF3DRenderer : public vtkOpenGLRenderer double ColorRange[2] = { 0.0, 1.0 }; bool ColorTransferFunctionConfigured = false; + bool EnableColoring = false; bool UseCellColoring = false; - int ArrayIndexForColoring = -1; int ComponentForColoring = -1; + std::optional ArrayNameForColoring; bool ScalarBarVisible = false; bool UsePointSprites = false;