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

Colormap parse format #2066

Merged
merged 10 commits into from
Mar 25, 2025
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 application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ f3d_test(NAME TestIncorrectComponent DATA dragon.vtu ARGS -s --coloring-componen
f3d_test(NAME TestIncorrectMultiFileVolume DATA multi ARGS -sv --coloring-array=Normals --multi-file-mode=all REGEXP "Cannot find the array \"Normals\" to display volume with" NO_BASELINE)

# Incorrect color map
f3d_test(NAME TestIncorrectColormap DATA IM-0001-1983.dcm ARGS --scalar-coloring --roughness=1 --colormap=0,1,0,0,1,0,1 REGEXP "Specified color map list count is not a multiple of 4, ignoring it." NO_BASELINE)
f3d_test(NAME TestIncorrectColormap DATA IM-0001-1983.dcm ARGS --scalar-coloring --roughness=1 --colormap=0,1,0,0,1,0,1 REGEXP "Incorrect number of tokens in provided colormap" NO_BASELINE)

# Test opening a directory
f3d_test(NAME TestVerboseDirectory DATA mb REGEXP "mb_0_0.vtu" NO_RENDER)
Expand Down
2 changes: 1 addition & 1 deletion doc/GALLERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ _Raytraced CAD assembly_: `f3d 202.vtp -xtgans -rd --raytracing-samples=10 --col

<img src="https://user-images.githubusercontent.com/3129530/194735377-127fa5d8-ece5-40c7-8176-672279ebdacc.png" width="700">

_Volume rendering of a security bag scan_: `f3d backpack.vti -vmn --coloring-range=300,1000 --colormap=0,0,0,0,1,1,1,1`
_Volume rendering of a security bag scan_: `f3d backpack.vti -vmn --coloring-range=300,1000 --colormap=0,#000000,1,#ffffff`

<img src="https://user-images.githubusercontent.com/3129530/194735376-3a476643-00d6-4cfc-9a88-e0dd33658564.png" width="700">

Expand Down
48 changes: 24 additions & 24 deletions doc/libf3d/OPTIONS.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions doc/user/COLOR_MAPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ Here's the list of all supported image formats that can be used as color maps:

## Custom values

If no colormap file is specified, it is also possible to set values manually using the `--colormap` option. A list of numbers between 0 and 1 must be specified. The size of the list is a multiple of 4 and each 4-components tuple correspond to the scalar value, followed by the RGB color.
For example, the default value corresponds to the `hot` preset which can be defined manually with `--colormap=0.0,0.0,0.0,0.0,0.4,0.9,0.0,0.0,0.8,0.9,0.9,0.0,1.0,1.0,1.0,1.0`.
If no colormap file is specified, it is also possible to set values manually using the `--colormap` option with a dedicated [parsing](PARSING.md#colormap).
For example, the default value corresponds to the `hot` preset which can be defined manually with `--colormap=0.0,rgb(0,0,0),0.4,rgb(230,0,0),0.8,rgb(230,230,0),1.0,rgb(255,255,255)`.
It consists of 4 tuples:

| Value | RGB |
| ----- | ----------------------------------------------------------------- |
| 0.0 | <span style="color:rgb(0,0,0)">&#9632;</span> 0.0, 0.0, 0.0 |
| 0.4 | <span style="color:rgb(230,0,0)">&#9632;</span> 0.9, 0.0, 0.0 |
| 0.8 | <span style="color:rgb(230,230,0)">&#9632;</span> 0.9, 0.9, 0.0 |
| 1.0 | <span style="color:rgb(255,255,255)">&#9632;</span> 1.0, 1.0, 1.0 |
| 0.0 | <span style="color:rgb(0,0,0)">&#9632;</span> 0, 0, 0 |
| 0.4 | <span style="color:rgb(230,0,0)">&#9632;</span> 230, 0, 0 |
| 0.8 | <span style="color:rgb(230,230,0)">&#9632;</span> 230, 230, 0 |
| 1.0 | <span style="color:rgb(255,255,255)">&#9632;</span> 255, 255, 255 |

Values in between are interpolated.
2 changes: 1 addition & 1 deletion doc/user/OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ F3D behavior can be fully controlled from the command line using the following o
| \-\-range=\<min,max\> | vector\<double\><br>- | Set the _coloring range_. Automatically computed by default.<br>Use with the scalar option. |
| -b, \-\-bar | bool<br>false | Show _scalar bar_ of the coloring by array.<br>Use with the scalar option. |
| \-\-colormap\-file=\<name\> | string<br>- | Set a _colormap file for the coloring_.<br>See [color maps](COLOR_MAPS.md).<br>Use with the scalar option. |
| \-\-colormap=\<color_list\> | string<br>- | Set a _custom colormap for the coloring_.<br>This is a list of colors in the format `val1,red1,green1,blue1,...,valN,redN,greenN,blueN`<br>where all values are in the range (0,1).<br>Ignored if `--colormap-file` option is specified.<br>Use with the scalar option. |
| \-\-colormap=\<colormap\> | colormap<br>- | Set a _custom colormap for the coloring_.See [colormap parsing](PARSING.md#colormap) for details.<br>Ignored if `--colormap-file` option is specified.<br>Use with the scalar option. |
| -v, \-\-volume | bool<br>false | 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 | bool<br>false | Inverse the linear opacity function used for volume rendering. |

Expand Down
9 changes: 9 additions & 0 deletions doc/user/PARSING.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,12 @@ The following formats are supported when parsing a string into a direction:
- vector of three doubles, for example `1,2,3.4`

When formatting a direction into a string, it is formatted in the `±XYZ` form if possible or as a vector of doubles otherwise.

## Colormap

The following formats are supported when parsing a string into a colormap:

- `val, red, green, blue, ...`
- `val, color, ...`

When formatting a colormap into a string, it is formatted as `val, color, ...`.
103 changes: 89 additions & 14 deletions library/private/options_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
{
static_assert(is_vector<T>::value, "non-vector types parsing must be specialized");

// TODO implement more parsing possibilities, eg different types of tokens
T vec;
std::istringstream split(str);
for (std::string each; std::getline(split, each, ',');)
Expand Down Expand Up @@ -403,24 +402,94 @@
//----------------------------------------------------------------------------
/**
* Parse provided string into a colormap_t.
* Supported formats: vector of doubles
* Supported formats:
* - "val, color, val, color, ..."
* - "val, red, green, blue, val, red, green, blue, ..."
* Where val is in [0, 1].
* Can throw options::parsing_exception in case of failure to parse
* TODO add proper parsing
*/
template<>
colormap_t parse(const std::string& str)
{
try
{
return colormap_t(options_tools::parse<std::vector<double>>(str));
}
catch (const options::parsing_exception&)
// Split by separator
std::vector<double> colormapVec;
std::istringstream split(str);
std::string each;
while (std::getline(split, each, ','))
{
throw options::parsing_exception("Cannot parse " + str + " into a colormap_t");
// Parse val into a double
double val;
try
{
val = options_tools::parse<double>(each);
}
catch (const options::parsing_exception&)
{
throw options::parsing_exception("Cannot parse value from colormap: " + each +
". Check provided colormap string is correct: " + str);
}

// Check it is between 0 and 1
if (val < 0 || val > 1)
{
throw options::parsing_exception("Parsed value from colormap: " + each +
" is not in expected [0, 1] range. Check provided colormap string is correct: " + str);
}

// Add value to colormap vector;
colormapVec.emplace_back(val);

// recover next string token
if (!std::getline(split, each, ','))
{
throw options::parsing_exception("Incorrect number of tokens in provided colormap: " + str);

Check warning on line 445 in library/private/options_tools.h

View check run for this annotation

Codecov / codecov/patch

library/private/options_tools.h#L445

Added line #L445 was not covered by tests
}

// Try to parse it directly as a color
f3d::color_t color;
try
{
color = options_tools::parse<f3d::color_t>(each);

// Add color to colormap vector
colormapVec.emplace_back(color.r());
colormapVec.emplace_back(color.g());
colormapVec.emplace_back(color.b());
continue;
}
catch (const options::parsing_exception&)
{
// Quiet catch
}

// Not a color, recover next two token, reconstruct r,g,b string and try to parse it as a color
// again
std::string green;
std::string blue;
if (!std::getline(split, green, ',') || !std::getline(split, blue, ','))
{
throw options::parsing_exception("Incorrect number of tokens in provided colormap or a color "
"could not be parsed as expected: " +
str);
}

try
{
color = options_tools::parse<f3d::color_t>(each + "," + green + "," + blue);
colormapVec.emplace_back(color.r());
colormapVec.emplace_back(color.g());
colormapVec.emplace_back(color.b());
continue;
}
catch (const options::parsing_exception&)
{
throw options::parsing_exception("Cannot parse color from colormap: " + each + "," + green +
"," + blue + ". Check provided colormap string is correct: " + str);
}
}
return colormap_t(colormapVec);
}

// TODO Improve string generation
//----------------------------------------------------------------------------
/**
* Format provided var into a string from provided boolean
Expand Down Expand Up @@ -461,7 +530,6 @@
*/
std::string format(ratio_t var)
{
// TODO generate a proper ratio string
return options_tools::format(static_cast<double>(var));
}

Expand Down Expand Up @@ -586,12 +654,19 @@
//----------------------------------------------------------------------------
/**
* Format provided var into a string from provided colormap_t.
* Rely on `format(std::vector<double>&)`
* TODO add proper formatting
* Rely on `format(double)` and `format(color_t)`
*/
std::string format(const colormap_t& var)
{
return options_tools::format(static_cast<std::vector<double>>(var));
std::ostringstream stream;
std::vector<double> vec(var);
size_t size = vec.size() / 4;
for (unsigned int i = 0; i < size; i++)
{
stream << ((i > 0) ? "," : "") << options_tools::format(vec[i * 4]) << ","
<< options_tools::format(color_t(vec[i * 4 + 1], vec[i * 4 + 2], vec[i * 4 + 3]));
}
return stream.str();
}

} // option_tools
Expand Down
3 changes: 1 addition & 2 deletions library/public/options.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ public:

/**
* Set an option as a string based on its name
* Use dedicated parsing code, see the related doc
* TODO add parsing documentation
* Use dedicated parsing code, see the related doc in PARSING.md.
* Throw an options::inexistent_exception if option does not exist.
* Throw an options::parsing_exception if parsing failed.
*/
Expand Down
8 changes: 4 additions & 4 deletions library/testing/TestSDKOptions.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ int TestSDKOptions(int argc, char* argv[])

// Test colormap_t
opt.setAsString("model.scivis.colormap", "0,0,0,0,1,1,1,1");
test("setAsString colormap", opt.getAsString("model.scivis.colormap"), "0,0,0,0,1,1,1,1");
test("setAsString colormap", opt.getAsString("model.scivis.colormap"), "0,#000000,1,#ffffff");

opt.setAsString("model.scivis.colormap", "0,0, 0,0, 1,0, 1,1");
test(
"setAsString spaces colormap", opt.getAsString("model.scivis.colormap") == "0,0,0,0,1,0,1,1");
test("setAsString spaces colormap",
opt.getAsString("model.scivis.colormap") == "0,#000000,1,#00ffff");

opt.model.scivis.colormap = { 0, 0, 0, 0, 1, 1, 0, 1 };
test("getAsString colormap", opt.getAsString("model.scivis.colormap") == "0,0,0,0,1,1,0,1");
test("getAsString colormap", opt.getAsString("model.scivis.colormap") == "0,#000000,1,#ff00ff");

opt.set("model.scivis.colormap", std::vector<double>{ 0, 0, 0, 0, 1, 1, 1, 0 });
test("set/get colormap",
Expand Down
17 changes: 16 additions & 1 deletion library/testing/TestSDKOptionsIO.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ int TestSDKOptionsIO(int argc, char* argv[])
test.parse_expect<f3d::color_t, parsing_exception>("invalid format color_t", "hxb(240,0%,0%)");
test.parse_expect<f3d::color_t, parsing_exception>("invalid color_t", "cmyk(200%,12%,34%,56%)");
test.parse_expect<f3d::color_t, parsing_exception>("incorrect size color_t", "0.1,0.2,0.3,0.4");
test.format<f3d::color_t>("color_t", { 1, 0, 1 }, "#ff00ff");
test.format<f3d::color_t>("color_t", { 0.1, 0.2, 0.3 }, "0.1,0.2,0.3");
test.format<f3d::color_t>("color_t", { 0, 0, 0 }, "#000000");
test.format<f3d::color_t>("color_t", { 1, 0, 1 }, "#ff00ff");
Expand Down Expand Up @@ -184,9 +185,23 @@ int TestSDKOptionsIO(int argc, char* argv[])
test.parse<f3d::colormap_t>("colormap_t", "0,0,0,0,1,1,1,1", { 0, 0, 0, 0, 1, 1, 1, 1 });
test.parse<f3d::colormap_t>(
"colormap_t", " -0.0, 0, 0 , 0.0,1,1.0 ,1, 1.0 ", { 0, 0, 0, 0, 1, 1, 1, 1 });
test.parse<f3d::colormap_t>("colormap_t", "0,#ff00ff,.2,#abcdef,0.8,#0000ff",
{ 0, 1, 0, 1, 0.2, static_cast<double>(171. / 255.), static_cast<double>(205. / 255.),
static_cast<double>(239. / 255.), 0.8, 0, 0, 1 });
test.parse_expect<f3d::colormap_t, parsing_exception>(
"invalid parsing colormap_t", "zero,0,0,0,one,1,1,1");
test.format<f3d::colormap_t>("colormap_t", { 0, 0, 0, 0, 1, 1, 1, 1 }, "0,0,0,0,1,1,1,1");
test.parse_expect<f3d::colormap_t, parsing_exception>(
"invalid parsing colormap_t val < [0,1] range", "-1,0,0,0,1,1,1,1");
test.parse_expect<f3d::colormap_t, parsing_exception>(
"invalid parsing colormap_t [0,1] < val range", "0,0,0,0,2,1,1,1");
test.parse_expect<f3d::colormap_t, parsing_exception>(
"incorrect number of tokens", "0,0,0,0,1,1,1");
test.parse_expect<f3d::colormap_t, parsing_exception>("invalid color", "0,0,0,0,1,1,1,invalid");

test.format<f3d::colormap_t>(
"colormap_t", { 0, 0, 0, 0, 0.5, 0, 1, 1, 0.9, 1, 1, 0 }, "0,#000000,0.5,#00ffff,0.9,#ffff00");
test.format<f3d::colormap_t>(
"colormap_t", { 0, 0.1, 0.2, 0.3, 1, 0.3, 0.2, 0.1 }, "0,0.1,0.2,0.3,1,0.3,0.2,0.1");

test.parse<std::vector<std::string>>(
"std::vector<std::string>", "foo,bar,baz", { "foo", "bar", "baz" });
Expand Down
4 changes: 4 additions & 0 deletions vtkext/private/module/Testing/TestF3DRendererWithColoring.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ int TestF3DRendererWithColoring(int argc, char* argv[])
return EXIT_FAILURE;
}

// Check invalid colormap code path
renderer->SetColormap({ 0, 0, 0 });
renderer->UpdateActors();

// Smoke test for deprecated HDRI collapse codepath
// F3D_DEPRECATED
renderer->SetHDRIFile("path/not/valid/../../to/file.ext");
Expand Down