Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use std::optional for options #1617

Merged
merged 28 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ F3D (pronounced `/fɛd/`) is a fast and minimalist 3D viewer desktop application

It is fully controllable from the command line and support configuration files. It can provide thumbnails, support interactive hotkeys, drag&drop and integration into file managers.

F3D also contains the libf3d, a simple library to render meshes, with C++ and Python Bindings, as well as experimental Java and Javascript bindings.
F3D also contains the libf3d, a simple library to render meshes, with a C++17 API, Python Bindings, and experimental Java and Javascript bindings.

<img src="https://user-images.githubusercontent.com/3129530/194735416-3f386437-456c-4145-9b5e-6bb6451d7e9a.png" width="640">

Expand Down
20 changes: 11 additions & 9 deletions application/F3DOptionsTools.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{ "up", "", "Up direction", "{-X, +X, -Y, +Y, -Z, +Z}", "" },
{ "axis", "x", "Show axes", "<bool>", "1" }, { "grid", "g", "Show grid", "<bool>", "1" },
{ "grid-absolute", "", "Position grid at the absolute origin instead of below the model", "<bool>", "1" },
{ "grid-unit", "", "Size of grid unit square, set to a non-positive value for automatic computation", "<value>", "" },
{ "grid-unit", "", "Size of grid unit square, automatically computed by default", "<value>", "" },
{ "grid-subdivisions", "", "Number of grid subdivisions", "<value>", "" },
{ "grid-color", "", "Color of main grid lines", "<R,G,B>", "" },
{ "edges", "e", "Show cell edges", "<bool>", "1" },
Expand All @@ -97,10 +97,11 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{"font-file", "", "Path to a FreeType compatible font file", "<file_path>", ""} } },
{ "Material",
{ {"point-sprites", "o", "Show sphere sprites instead of geometry", "<bool>", "1" },
{"point-type", "", "Point sprites type when showing point sprites", "<sphere|gaussian>", ""},
{"point-size", "", "Point size when showing vertices or point sprites", "<size>", ""},
{"line-width", "", "Line width when showing edges", "<width>", ""},
{"backface-type", "", "Backface type, can be default (usually visible), visible or hidden", "<default|visible|hidden>", ""},
{"point-sprites-type", "", "Point sprites type", "<sphere|gaussian>", ""},
{"point-sprites-size", "", "Point sprites size", "<size>", ""},
{"point-size", "", "Point size when showing vertices, model specified by default", "<size>", ""},
{"line-width", "", "Line width when showing edges, model specified by default", "<width>", ""},
{"backface-type", "", "Backface type, can be visible or hidden, model specified by default", "<visible|hidden>", ""},
{"color", "", "Solid color", "<R,G,B>", ""},
{"opacity", "", "Opacity", "<opacity>", ""},
{"roughness", "", "Roughness coefficient (0.0-1.0)", "<roughness>", ""},
Expand Down Expand Up @@ -130,7 +131,7 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{"coloring-array", "", "Name of the array to color with", "<array_name>", "" },
{"comp", "y", "Component from the array to color with. -1 means magnitude, -2 or the short option, -y, means direct scalars", "<comp_index>", "-2"},
{"cells", "c", "Use an array from the cells", "<bool>", "1"},
{"range", "", "Custom range for the coloring by array", "<min,max>", ""},
{"range", "", "Custom range for the coloring by array, automatically computed by default", "<min,max>", ""},
{"bar", "b", "Show scalar bar", "<bool>", "1" },
{"colormap-file", "", "Specify a colormap image", "<filePath/filename/fileStem>", ""},
{"colormap", "", "Specify a custom colormap (ignored if \"colormap-file\" is specified)", "<color_list>", ""},
Expand Down Expand Up @@ -390,8 +391,7 @@ std::pair<std::string, int> F3DOptionsTools::GetClosestOption(const std::string&
// Check libf3d option names
if (checkLib)
{
f3d::options opt;
for (const std::string& key : opt.getNames())
for (const std::string& key : f3d::options::getAllNames())
{
checkDistance(key, option, ret);
}
Expand Down Expand Up @@ -450,7 +450,9 @@ F3DOptionsTools::OptionsDict F3DOptionsTools::ParseCLIOptions(
if (libIter != F3DOptionsTools::LibOptionsNames.end())
{
f3d::options opt;
defaultValue = opt.getAsString(std::string(libIter->second));
std::string name = std::string(libIter->second);
Meakk marked this conversation as resolved.
Show resolved Hide resolved
// let default value empty for unset options
defaultValue = opt.hasValue(name) ? opt.getAsString(name) : "";
}
}

Expand Down
3 changes: 2 additions & 1 deletion application/F3DOptionsTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ static inline const std::map<std::string_view, std::string_view> LibOptionsNames
{ "animation-frame-rate", "scene.animation.frame_rate" },
{ "font-file", "ui.font_file" },
{ "point-sprites", "model.point_sprites.enable" },
{ "point-type", "model.point_sprites.type" },
{ "point-sprites-type", "model.point_sprites.type" },
mwestphal marked this conversation as resolved.
Show resolved Hide resolved
{ "point-sprites-size", "model.point_sprites.size" },
{ "point-size", "render.point_size" },
{ "line-width", "render.line_width" },
{ "backface-type", "render.backface_type" },
Expand Down
5 changes: 4 additions & 1 deletion application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -957,11 +957,14 @@ void F3DStarter::LoadFile(int index, bool relativeIndex)
// Detect interactively changed options and store them into the dynamic options dict
// options names are shared between options instance
F3DOptionsTools::OptionsDict dynamicOptionsDict;
std::vector<std::string> optionNames = this->Internals->LibOptions.getNames();
std::vector<std::string> optionNames = dynamicOptions.getNames();
for (const auto& name : optionNames)
{
if (!dynamicOptions.isSame(this->Internals->LibOptions, name))
{
// XXX Currently an assert is enough but it should be a proper try/catch once
// we add a mechanism to unset an option
assert(dynamicOptions.hasValue(name));
dynamicOptionsDict[name] = dynamicOptions.getAsString(name);
}
}
Expand Down
25 changes: 17 additions & 8 deletions application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ f3d_test(NAME TestVTS DATA bluntfin.vts)
f3d_test(NAME TestVTM DATA mb.vtm)
f3d_test(NAME TestVTK DATA cow.vtk)
f3d_test(NAME TestNRRD DATA beach.nrrd ARGS -s)
f3d_test(NAME TestSPLAT DATA small.splat ARGS -osy --up=-Y --point-size=1)
f3d_test(NAME TestSPLAT DATA small.splat ARGS -osy --up=-Y --point-sprites-size=1)
f3d_test(NAME TestGridX DATA suzanne.ply ARGS -g --up=+X)
f3d_test(NAME TestGridY DATA suzanne.ply ARGS -g --up=+Y)
f3d_test(NAME TestGridZ DATA suzanne.ply ARGS -g --up=+Z)
Expand All @@ -137,9 +137,9 @@ f3d_test(NAME TestGridColor DATA suzanne.ply ARGS -g --grid-color=1,1,1)
f3d_test(NAME TestAxis DATA suzanne.ply ARGS -x)
f3d_test(NAME TestBackfaceVisible DATA backface.vtp ARGS --backface-type=visible)
f3d_test(NAME TestBackfaceHidden DATA backface.vtp ARGS --backface-type=hidden)
f3d_test(NAME TestPointCloud DATA pointsCloud.vtp ARGS -o --point-size=20)
f3d_test(NAME TestPointCloudBar DATA pointsCloud.vtp ARGS -sob --point-size=20)
f3d_test(NAME TestPointCloudUG DATA pointsCloud.vtu ARGS -o --point-size=20)
f3d_test(NAME TestPointCloud DATA pointsCloud.vtp ARGS -o --point-sprites-size=20)
f3d_test(NAME TestPointCloudBar DATA pointsCloud.vtp ARGS -sob --point-sprites-size=20)
f3d_test(NAME TestPointCloudUG DATA pointsCloud.vtu ARGS -o --point-sprites-size=20)
f3d_test(NAME TestPointCloudVolume DATA bluntfin.vts ARGS -sob)
f3d_test(NAME TestPointCloudDefaultScene DATA pointsCloud.vtp ARGS --point-size=20)
f3d_test(NAME Test3DSImporter DATA iflamigm.3ds ARGS --up=+Z)
Expand Down Expand Up @@ -287,7 +287,7 @@ endif()
# Needs splat sorting with compute shaders
if(VTK_VERSION VERSION_GREATER_EQUAL 9.3.20240203)
if(NOT APPLE) # MacOS does not support compute shaders
f3d_test(NAME Test3DGaussiansSplatting DATA small.splat ARGS -osy --up=-Y --point-size=1 --point-type=gaussian --camera-position=-3.6,0.5,-4.2)
f3d_test(NAME Test3DGaussiansSplatting DATA small.splat ARGS -osy --up=-Y --point-sprites-size=1 --point-sprites-type=gaussian --camera-position=-3.6,0.5,-4.2)
f3d_test(NAME TestDefaultConfigFileSPLAT DATA small.splat CONFIG config_build LONG_TIMEOUT)
f3d_test(NAME TestThumbnailConfigFileSPLAT DATA small.splat CONFIG thumbnail_build LONG_TIMEOUT)
endif()
Expand Down Expand Up @@ -612,8 +612,11 @@ if(F3D_PLUGIN_BUILD_EXODUS)
f3d_test(NAME TestAnimationTimeLimitsHigh DATA small.ex2 ARGS ARGS --load-plugins=exodus --animation-time=10)
f3d_test(NAME TestAnimationTimeLimitsLow DATA small.ex2 ARGS ARGS --load-plugins=exodus --animation-time=-5)

# Test if negative range is respected when loading a file without specifying the animation time
f3d_test(NAME TestTimeRangeLessThanZeroNoAnimationTime DATA negative_range_animated.e ARGS -s --load-plugins=exodus)

# Test if the animation-time works when set to zero and time range[0] is less than zero
f3d_test(NAME TestTimeRangeLessThanZero DATA negative_range_animated.e ARGS -s --load-plugins=exodus --animation-time=0)
f3d_test(NAME TestTimeRangeLessThanZeroWithAnimationTime DATA negative_range_animated.e ARGS -s --load-plugins=exodus --animation-time=0)

# Test if a negative animation-time works when time range[0] is less than zero
f3d_test(NAME TestTimeRangeLessThanZeroNegativeAnimationTime DATA negative_range_animated.e ARGS -s --load-plugins=exodus --animation-time=-3)
Expand Down Expand Up @@ -721,7 +724,7 @@ 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 TestInteractionVolumeInverse DATA HeadMRVolume.mhd ARGS --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 INTERACTION) #VI
f3d_test(NAME TestInteractionPointCloud DATA pointsCloud.vtp ARGS --point-size=20 INTERACTION) #O
f3d_test(NAME TestInteractionPointCloud DATA pointsCloud.vtp ARGS --point-sprites-size=20 INTERACTION) #O
f3d_test(NAME TestInteractionDirectory DATA mb INTERACTION ARGS --scalar-coloring) #Right;Right;Right;Left;Up;
f3d_test(NAME TestInteractionDirectoryLoop DATA mb INTERACTION ARGS --scalar-coloring) #Left;Left;Left;
f3d_test(NAME TestInteractionDirectoryEmpty DATA mb INTERACTION NO_DATA_FORCE_RENDER) #Right;Right;Right;
Expand Down Expand Up @@ -821,7 +824,7 @@ f3d_test(NAME TestVerboseDebug DATA dragon.vtu ARGS --verbose REGEXP "Number of
f3d_test(NAME TestVerboseInvalid DATA dragon.vtu ARGS --verbose=invalid REGEXP "Unrecognized verbose level" NO_BASELINE)

# Unknown scalar array verbosity test
f3d_test(NAME TestVerboseWrongArray DATA dragon.vtu ARGS -s --coloring-array=dummy --verbose REGEXP "Unknown scalar array: dummy" NO_BASELINE)
f3d_test(NAME TestVerboseWrongArray DATA dragon.vtu ARGS -s --coloring-array=dummy --verbose REGEXP "Unknown scalar array: \"dummy\"" NO_BASELINE)

# 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)
Expand Down Expand Up @@ -864,6 +867,12 @@ f3d_test(NAME TestVerboseVolumeNoArray DATA cow.vtp ARGS -v REGEXP "Cannot use v
# Test scalar rendering without any array
f3d_test(NAME TestVerboseNoArray DATA cow.vtp ARGS -s --verbose=debug REGEXP "No array to color with" NO_BASELINE)

# Test invalid scalar range
f3d_test(NAME TestInvalidScalarsRange DATA suzanne.ply ARGS -s --coloring-array=Normals --comp=1 --range=0,1,2 REGEXP "Invalid scalar range provided, using automatic range" NO_BASELINE)

# Test invalid backface type
f3d_test(NAME TestInvalidBackface DATA backface.vtp ARGS --backface-type=invalid REGEXP "is not a valid backface type, assuming it is not set" NO_BASELINE)

# Test non existent file, do not create nonExistentFile.vtp
f3d_test(NAME TestVerboseNonExistentFile DATA nonExistentFile.vtp REGEXP "File .*nonExistentFile.vtp does not exist" NO_RENDER)

Expand Down
27 changes: 21 additions & 6 deletions cmake/f3dOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,17 +98,22 @@ function(_parse_json_option _top_json)
# Read the json element
string(JSON _cur_json GET ${_top_json} ${_member_name})
# Recover its type and default if it is a leaf option
string(JSON _option_type ERROR_VARIABLE _type_error GET ${_cur_json} "type")
string(JSON _option_default_value ERROR_VARIABLE _default_value_error GET ${_cur_json} "default_value")
if(_type_error STREQUAL "NOTFOUND" AND _default_value_error STREQUAL "NOTFOUND")
string(JSON _option_type ERROR_VARIABLE _option_type_error GET ${_cur_json} "type")
string(JSON _option_type_type ERROR_VARIABLE _option_type_type_error TYPE ${_cur_json} "type")
if(_option_type_error STREQUAL "NOTFOUND" AND ${_option_type_type} STREQUAL "STRING")
# Leaf option found!

# Recover default_value if any
string(JSON _option_default_value ERROR_VARIABLE _default_value_error GET ${_cur_json} "default_value")

set(_option_name "${_option_basename}${_member_name}")

# Identify types
set(_option_actual_type ${_option_type})
set(_option_variant_type ${_option_type})
set(_option_default_value_start "")
set(_option_default_value_end "")

if(_option_type STREQUAL "double_vector")
set(_option_actual_type "std::vector<double>")
set(_option_variant_type "std::vector<double>")
Expand All @@ -125,11 +130,21 @@ function(_parse_json_option _top_json)
endif()

# Add option to struct and methods
string(APPEND _options_struct "${_option_indent} ${_option_actual_type} ${_member_name} = ${_option_default_value_start}${_option_default_value}${_option_default_value_end};\n")

if(_default_value_error STREQUAL "NOTFOUND")
# Use default_value
string(APPEND _options_struct "${_option_indent} ${_option_actual_type} ${_member_name} = ${_option_default_value_start}${_option_default_value}${_option_default_value_end};\n")
set(_optional_getter "")
else()
# No default_value, it is an std::optional
string(APPEND _options_struct "${_option_indent} std::optional<${_option_actual_type}> ${_member_name};\n")
set(_optional_getter ".value()")
endif()

list(APPEND _options_setter "if (name == \"${_option_name}\") opt.${_option_name} = std::get<${_option_variant_type}>(value)")
list(APPEND _options_getter "if (name == \"${_option_name}\") return opt.${_option_name}")
list(APPEND _options_getter "if (name == \"${_option_name}\") return opt.${_option_name}${_optional_getter}")
list(APPEND _options_string_setter "if (name == \"${_option_name}\") opt.${_option_name} = options_tools::parse<${_option_actual_type}>(str)")
list(APPEND _options_string_getter "if (name == \"${_option_name}\") return options_tools::format(opt.${_option_name})")
list(APPEND _options_string_getter "if (name == \"${_option_name}\") return options_tools::format(opt.${_option_name}${_optional_getter})")
list(APPEND _options_lister "\"${_option_name}\"")

else()
Expand Down
2 changes: 1 addition & 1 deletion doc/GALLERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Images and videos displayed below use public datasets, you can download them [he

<video src='https://media.githubusercontent.com/media/f3d-app/f3d-media/main/media/counter.webm' autoplay="autoplay" loop="loop" width="700"></video>

*3D Gaussians Splatting*: `f3d counter.splat --point-size=1 --point-type=gaussian -soynxz --up=-Y --camera-position=0,1,-5.2 --camera-focal-point=0,1,0`
*3D Gaussians Splatting*: `f3d counter.splat --point-sprites-size=1 --point-sprites-type=gaussian -soynxz --up=-Y --camera-position=0,1,-5.2 --camera-focal-point=0,1,0`

<img src="https://user-images.githubusercontent.com/3129530/194735272-5bcd3e7c-a333-41f5-8066-9b0bec9885e8.png" width="700">

Expand Down
Loading