RescaleReverseLUT
Repository source: RescaleReverseLUT
Description¶
This example shows how to adjust a colormap so that the colormap scalar range matches the scalar range on the object. This is done by adjusting the colormap so that the colormap scalar range matches the scalar range of the object by rescaling the control points and, optionally, reversing the order of the colors.
Of course, if you are generating the scalars, it may be easier to just change the scalar range of your filter. However, this may not be possible in some cases.
Here, we generate the original Color Transfer Function (CTF) corresponding to the seven colors that Isaac Newton labeled when dividing the spectrum of visible light in 1672. There are seven colors and the scalar range is [-1, 1].
The cylinder has a vtkElevationFilter applied to it with a scalar range of [0, 1].
There are four images:
- Original - The cylinder is colored by only the top four colors from the CTF. This is because the elevation scalar range on the cylinder is [0, 1] and the CTF scalar range is [-1, 1]. So the coloring is green->violet.
- Reversed - We have reversed the colors from the original CTF and the lower four colors in the original CTF are now the top four colors used to color the cylinder. The coloring is now green->red.
- Rescaled - The original CTF is rescaled to the range [0, 1] to match the scalar range of the elevation filter. The coloring is red->violet.
- Rescaled and Reversed - The original CTF is rescaled to the range [0, 1] and the colors reversed. The coloring is violet->red.
Other languages
See (Python), (PythonicAPI)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
RescaleReverseLUT.cxx
#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkCylinderSource.h>
#include <vtkDiscretizableColorTransferFunction.h>
#include <vtkElevationFilter.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkScalarBarActor.h>
#include <vtkScalarBarRepresentation.h>
#include <vtkScalarBarWidget.h>
#include <vtkSmartPointer.h>
#include <vtkTextActor.h>
#include <vtkTextMapper.h>
#include <vtkTextProperty.h>
#include <vtkTextRepresentation.h>
#include <vtkTextWidget.h>
#include <vtk_cli11.h>
#include <vtk_fmt.h>
// clang-format off
#include VTK_FMT(fmt/format.h)
// clang-format on
// #include <algorithm>
// #include <array>
// #include <cctype>
// #include <cmath>
// #include <cstdlib>
// #include <filesystem>
// #include <functional>
// #include <iomanip>
// #include <iostream>
// #include <iterator>
// #include <map>
// #include <numeric>
// #include <sstream>
namespace fs = std::filesystem;
namespace {
/**
* Generate the color transfer function.
*
* The seven colors corresponding to the colors that Isaac Newton labelled
* when dividing the spectrum of visible light in 1672 are used.
*
* The modern variant of these colors can be selected and used instead.
*
* See: [Rainbow](https://en.wikipedia.org/wiki/Rainbow)
*
* @param modern: Selects either Newton's original seven colors or the modern
* version.
* @param discretize: Selects whether the CTF is discretized or not.
*
* @return The color transfer function.
*/
vtkNew<vtkDiscretizableColorTransferFunction>
GetCTF(bool const& modern = false, bool const& discretize = true);
/**
* Generate a new color transfer function from the old one,
* adding in the new x and rgb values.
*
* @param oldCTF: The old color transfer function.
* @param newX: The new color x-values.
* @param newRGB: The color RGB values.
* @param discretize: Selects whether the CTF is discretized or not.
* @param reverse: If true, reverse the colors.
*
* @return The new color transfer function.
*/
vtkNew<vtkDiscretizableColorTransferFunction>
GenerateNewCTF(vtkNew<vtkDiscretizableColorTransferFunction> const& oldCTF,
std::vector<double> const& newX,
std::vector<std::array<double, 3>> const& newRGB,
bool const& discretise = true, bool const& reverse = false);
/**
* Rescale the values.
*
* See:
* https://stats.stackexchange.com/questions/25894/changing-the-scale-of-a-variable-to-0-100
*
* @param xv: The values to be rescaled.
* @param newMin: The new minimum value.
* @param newMax: The new maximum value.
*
* @return The rescaled values.
*/
std::vector<double> Rescale(std::vector<double> const& xv,
double const& newMin = 0, double const& newMax = 1);
/**
* Rescale and, optionally, reverse the colors in the color transfer function.
*
* @param ctf: The color transfer function to rescale.
* @param newMin: The new minimum value.
* @param newMax: The new maximum value.
* @param discretize: Selects whether the CTF is discretized or not.
* @param reverse: If true, reverse the colors.
*
* @return The rescaled color transfer function.
*/
vtkNew<vtkDiscretizableColorTransferFunction>
RescaleCTF(vtkNew<vtkDiscretizableColorTransferFunction> const& ctf,
double const& newMin = 0, double const& newMax = 1,
bool const& discretise = true, bool const& reverse = false);
typedef std::map<std::string, std::array<double, 2>> TTextPosition;
typedef std::map<std::string, TTextPosition> TTextPositions;
struct ScalarBarProperties
{
vtkSmartPointer<vtkNamedColors> colors;
// The properties needed for scalar bars.
vtkSmartPointer<vtkDiscretizableColorTransferFunction> lut;
// These are in pixels.
std::map<std::string, int> maximumDimensions{{"width", 100}, {"height", 260}};
std::string titleText{""};
int number_of_labels{7};
std::string labelFormat{"{:0.2f}"};
// Orientation vertical=true, horizontal=false.
bool orientation{true};
// Horizontal and vertical positioning.
// These are the defaults, don't change these.
TTextPosition defaultV = {{"p", {0.85, 0.1}}, {"p2", {0.1, 0.7}}};
TTextPosition defaultH = {{"p", {0.10, 0.1}}, {"p2", {0.7, 0.1}}};
// Modify these as needed.
TTextPosition positionV = {{"p", {0.75, 0.2}}, {"p2", {0.075, 0.7}}};
TTextPosition positionH = {{"p", {0.10, 0.1}}, {"p2", {0.7, 0.1}}};
};
/** Make a scalar bar widget.
*
* @param scalar_bar_properties - The lookup table, title name, maximum
* dimensions in pixels and position.
* @param textProperty - The properties for the title.
* @param labelTextProperty - The properties for the labels.
* @param ren - The vtkRenderer.
* @param iren - The vtkInteractor.
* @return The scalar bar widget.
*/
vtkNew<vtkScalarBarWidget>
MakeScalarBarWidget(ScalarBarProperties& scalarBarProperties,
vtkTextProperty* textProperty,
vtkTextProperty* labelTextProperty, vtkRenderer* ren,
vtkRenderWindowInteractor* iren);
/**
* Get viewport positioning information for a vector of names.
*
* Note: You must include vtkSystemIncludes.h to get these defines:
* VTK_TEXT_LEFT 0, VTK_TEXT_CENTERED 1, VTK_TEXT_RIGHT 2,
* VTK_TEXT_BOTTOM 0, VTK_TEXT_TOP 2
*
* @param names - The vector of names.
* @param justification - Horizontal justification of the text.
* @param verticalJustification - Vertical justification of the text.
* @param width - Width of the bounding_box of the text in screen coordinates.
* @param height - Height of the bounding_box of the text in screen
* coordinates.
* @return A map of positioning information.
*/
TTextPositions
GetTextPositions(std::vector<std::string> const& names,
int const justification = VTK_TEXT_LEFT,
int const verticalJustification = VTK_TEXT_BOTTOM,
double const width = 0.96, double const height = 0.1);
/** Convert a string to title case.
*
* @param input - The string to convert.
* @return The string converted to title case.
*/
std::string Title(const std::string& input);
} // namespace
int main(int argc, char* argv[])
{
CLI::App app{
"Demonstrates how to adjust the colormap scalar range and reverse it."};
// Define options
auto modern{false};
app.add_flag("-m, --modern", modern,
"Use the \"modern\" colors instead of Newtonian colors.");
auto compactification{false};
app.add_flag("-c, --compactification", compactification,
"Build a continuous colormap.");
CLI11_PARSE(app, argc, argv);
auto discretize = !compactification;
vtkNew<vtkNamedColors> colors;
colors->SetColor("ParaViewBlueGrayBkg",
std::array<unsigned char, 4>{84, 89, 109, 255}.data());
colors->SetColor("ParaViewWarmGrayBkg",
std::array<unsigned char, 4>{98, 93, 90, 255}.data());
vtkNew<vtkRenderWindow> renWin;
renWin->SetSize(640 * 2, 480 * 2);
auto appFn = fs::path((app.get_name())).stem().string();
renWin->SetWindowName(appFn.c_str());
vtkNew<vtkRenderWindowInteractor> iRen;
iRen->SetRenderWindow(renWin);
vtkNew<vtkInteractorStyleTrackballCamera> style;
iRen->SetInteractorStyle(style);
// Define viewport ranges.
std::array<double, 4> xMins{0.0, 0.0, 0.5, 0.5};
std::array<double, 4> xMaxs{0.5, 0.5, 1.0, 1.0};
std::array<double, 4> yMins{0.5, 0.0, 0.5, 0.0};
std::array<double, 4> yMaxs{1.0, 0.5, 1.0, 0.5};
// Define titles.
std::vector<std::string> titles{"Orginal", "Rescaled", "Reversed",
"Rescaled & Reversed"};
auto txtPos =
GetTextPositions(titles, VTK_TEXT_CENTERED, VTK_TEXT_BOTTOM, 0.45, 0.1);
std::map<std::string, TTextPosition> namePositions;
for (auto const& t : titles)
{
namePositions[t] = txtPos[t];
}
std::map<std::string, vtkNew<vtkDiscretizableColorTransferFunction>> ctf;
ctf[titles[0]] = GetCTF(modern, discretize);
const double* tmp = ctf[titles[0]]->GetRange();
ctf[titles[1]] = RescaleCTF(ctf[titles[0]], 0, 1, discretize);
ctf[titles[2]] = RescaleCTF(ctf[titles[0]], tmp[0], tmp[1], discretize, true);
ctf[titles[3]] = RescaleCTF(ctf[titles[0]], 0, 1, discretize, true);
// Create text properties.
vtkNew<vtkTextProperty> textProperty;
textProperty->SetColor(colors->GetColor3d("LightGoldenrodYellow").GetData());
textProperty->SetFontSize(16);
textProperty->BoldOff();
textProperty->ItalicOff();
textProperty->ShadowOff();
textProperty->SetJustificationToCentered();
textProperty->SetVerticalJustificationToCentered();
vtkNew<vtkTextProperty> titleTextProperty;
titleTextProperty->SetColor(
colors->GetColor3d("LightGoldenrodYellow").GetData());
titleTextProperty->SetFontSize(16);
titleTextProperty->BoldOff();
titleTextProperty->ItalicOff();
titleTextProperty->ShadowOff();
titleTextProperty->SetFontFamilyAsString("Courier");
titleTextProperty->SetJustificationToCentered();
titleTextProperty->SetVerticalJustificationToCentered();
vtkNew<vtkTextProperty> labelTextProperty;
labelTextProperty->SetColor(
colors->GetColor3d("LightGoldenrodYellow").GetData());
labelTextProperty->SetFontSize(16);
labelTextProperty->BoldOff();
labelTextProperty->ItalicOff();
labelTextProperty->ShadowOff();
labelTextProperty->SetJustificationToCentered();
labelTextProperty->SetVerticalJustificationToCentered();
vtkNew<vtkCylinderSource> cylinder;
cylinder->SetCenter(0.0, 0.0, 0.0);
cylinder->SetResolution(6);
cylinder->Update();
std::vector<vtkSmartPointer<vtkTextWidget>> textWidgets;
std::vector<vtkSmartPointer<vtkScalarBarWidget>> sbWidgets;
std::vector<vtkSmartPointer<vtkRenderer>> renderers;
auto replaceInStr = [](std::string& source, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = source.find(search, pos)) != std::string::npos)
{
source.replace(pos, search.length(), replace);
pos += replace.length(); // Move past the replaced section.
}
};
for (auto idx = 0; idx < static_cast<int>(titles.size()); ++idx)
{
std::string name = titles[idx];
double* bounds = cylinder->GetOutput()->GetBounds();
vtkNew<vtkElevationFilter> elevation_filter;
elevation_filter->SetScalarRange(0, 1);
elevation_filter->SetLowPoint(0, bounds[2], 0);
elevation_filter->SetHighPoint(0, bounds[3], 0);
elevation_filter->SetInputConnection(cylinder->GetOutputPort());
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(elevation_filter->GetOutputPort());
mapper->SetLookupTable(ctf[name]);
mapper->SetColorModeToMapScalars();
mapper->InterpolateScalarsBeforeMappingOn();
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> ren;
ren->SetBackground(colors->GetColor3d("ParaViewBlueGrayBkg").GetData());
ren->AddActor(actor);
ren->SetViewport(xMins[idx], yMins[idx], xMaxs[idx], yMaxs[idx]);
// Add a title.
vtkNew<vtkTextActor> textActor;
textActor->SetInput(name.c_str());
textActor->SetTextScaleModeToViewport();
textActor->SetTextProperty(titleTextProperty);
auto pos = namePositions[name];
// Create the text widget, setting the default renderer and interactor.
vtkNew<vtkTextRepresentation> textRepresentation;
textRepresentation->EnforceNormalizedViewportBoundsOn();
textRepresentation->SetPosition(pos["p"][0], pos["p"][1]);
textRepresentation->SetPosition2(pos["p2"][0], pos["p2"][1]);
vtkNew<vtkTextWidget> textWidget;
textWidget->SetRepresentation(textRepresentation);
textWidget->SetTextActor(textActor);
textWidget->SelectableOff();
textWidget->ResizableOn();
textWidget->SetDefaultRenderer(ren);
textWidget->SetInteractor(iRen);
textWidgets.push_back(textWidget);
// Create the scalar bar, setting the default renderer and interactor.
auto sbProperties = ScalarBarProperties();
std::string sbName = name;
replaceInStr(sbName, " & ", "\n");
sbProperties.titleText = sbName + '\n';
sbProperties.lut = ctf[name];
sbWidgets.push_back(MakeScalarBarWidget(sbProperties, titleTextProperty,
labelTextProperty, ren, iRen));
renderers.push_back(ren);
}
for (size_t idx = 0; idx < renderers.size(); ++idx)
{
renWin->AddRenderer(renderers[idx]);
textWidgets[idx]->On();
sbWidgets[idx]->On();
}
renWin->Render();
iRen->Start();
return EXIT_SUCCESS;
}
namespace {
vtkNew<vtkDiscretizableColorTransferFunction> GetCTF(bool const& modern,
bool const& discretise)
{
// name: Rainbow, creator: Andrew Maclean
// interpolationspace: RGB, space: rgb
// file name:
vtkNew<vtkDiscretizableColorTransferFunction> ctf;
ctf->SetColorSpaceToRGB();
ctf->SetScaleToLinear();
ctf->SetNanColor(0.5, 0.5, 0.5);
ctf->SetBelowRangeColor(0.0, 0.0, 0.0);
ctf->UseBelowRangeColorOn();
ctf->SetAboveRangeColor(1.0, 1.0, 1.0);
ctf->UseAboveRangeColorOn();
ctf->SetNumberOfValues(7);
if (discretise)
{
ctf->DiscretizeOn();
}
else
{
ctf->DiscretizeOff();
}
if (modern)
{
ctf->AddRGBPoint(-1.0, 1.0, 0.0, 0.0); // Red
ctf->AddRGBPoint(-2.0 / 3.0, 1.0, 128.0 / 255.0, 0.0); // Orange #ff8000
ctf->AddRGBPoint(-1.0 / 3.0, 1.0, 1.0, 0.0); // Yellow
ctf->AddRGBPoint(0.0, 0.0, 1.0, 0.0); // Green #00ff00
ctf->AddRGBPoint(1.0 / 3.0, 0.0, 1.0, 1.0); // Cyan
ctf->AddRGBPoint(2.0 / 3.0, 0.0, 0.0, 1.0); // Blue
ctf->AddRGBPoint(1.0, 128.0 / 255.0, 0.0, 1.0); // Violet #8000ff
}
else
{
ctf->AddRGBPoint(-1.0, 1.0, 0.0, 0.0); // Red
ctf->AddRGBPoint(-2.0 / 3.0, 1.0, 165.0 / 255.0, 0.0); // Orange #00a500
ctf->AddRGBPoint(-1.0 / 3.0, 1.0, 1.0, 0.0); // Yellow
ctf->AddRGBPoint(0.0, 0.0, 125.0 / 255.0, 0.0); // Green #008000
ctf->AddRGBPoint(1.0 / 3.0, 0.0, 153.0 / 255.0, 1.0); // Blue #0099ff
ctf->AddRGBPoint(2.0 / 3.0, 68.0 / 255.0, 0,
153.0 / 255.0); // Indigo #4400ff
ctf->AddRGBPoint(1.0, 153.0 / 255.0, 0.0, 1.0); // Violet #9900ff
}
ctf->Build();
return ctf;
}
vtkNew<vtkDiscretizableColorTransferFunction>
GenerateNewCTF(vtkNew<vtkDiscretizableColorTransferFunction> const& oldCTF,
std::vector<double> const& newX,
std::vector<std::array<double, 3>> const& newRGB,
bool const& discretise, bool const& reverse)
{
vtkNew<vtkDiscretizableColorTransferFunction> newCTF;
newCTF->SetColorSpace(oldCTF->GetColorSpace());
newCTF->SetScale(oldCTF->GetScale());
newCTF->SetNanColor(oldCTF->GetNanColor());
newCTF->SetNumberOfValues(newX.size());
if (discretise)
{
newCTF->DiscretizeOn();
}
else
{
newCTF->DiscretizeOff();
}
if (!reverse)
{
newCTF->SetBelowRangeColor(oldCTF->GetBelowRangeColor());
newCTF->SetUseBelowRangeColor(oldCTF->GetUseBelowRangeColor());
newCTF->SetAboveRangeColor(oldCTF->GetAboveRangeColor());
newCTF->SetUseAboveRangeColor(oldCTF->GetUseAboveRangeColor());
}
else
{
newCTF->SetBelowRangeColor(oldCTF->GetAboveRangeColor());
newCTF->SetUseBelowRangeColor(oldCTF->GetUseAboveRangeColor());
newCTF->SetAboveRangeColor(oldCTF->GetBelowRangeColor());
newCTF->SetUseAboveRangeColor(oldCTF->GetUseBelowRangeColor());
}
if (!reverse)
{
for (size_t i = 0; i < newX.size(); ++i)
{
newCTF->AddRGBPoint(newX[i], newRGB[i][0], newRGB[i][1], newRGB[i][2]);
}
}
else
{
auto sz = newX.size();
for (size_t i = 0; i < sz; i++)
{
auto j = sz - (i + 1);
newCTF->AddRGBPoint(newX[i], newRGB[j][0], newRGB[j][1], newRGB[j][2]);
}
}
newCTF->Build();
return newCTF;
}
std::vector<double> Rescale(std::vector<double> const& values,
double const& newMin, double const& newMax)
{
std::vector<double> res;
double oldMin = *std::min_element(values.begin(), values.end());
double oldMax = *std::max_element(values.begin(), values.end());
for (size_t i = 0; i < values.size(); ++i)
{
double newV =
(newMax - newMin) / (oldMax - oldMin) * (values[i] - oldMin) + newMin;
// double newV1 =
// (newMax - newMin) / (oldMax - oldMin) * (values[i] - oldMax) +
// newMax;
res.push_back(newV);
}
return res;
}
vtkNew<vtkDiscretizableColorTransferFunction>
RescaleCTF(vtkNew<vtkDiscretizableColorTransferFunction> const& ctf,
double const& newMin, double const& newMax, bool const& discretise,
bool const& reverse)
{
double r0;
double r1;
if (newMin > newMax)
{
r0 = newMax;
r1 = newMin;
}
else
{
r0 = newMin;
r1 = newMax;
}
std::vector<double> xv;
std::vector<std::array<double, 3>> rgbv;
double nv[6] = {0, 0, 0, 0, 0, 0};
for (auto i = 0; i < ctf->GetNumberOfValues(); ++i)
{
ctf->GetNodeValue(i, nv);
double x = nv[0];
std::array<double, 3> rgb;
for (auto j = 1; j < 4; ++j)
{
rgb[j - 1] = nv[j];
}
xv.push_back(x);
rgbv.push_back(rgb);
}
std::vector<double> xvr = Rescale(xv, r0, r1);
return GenerateNewCTF(ctf, xvr, rgbv, discretise, reverse);
}
vtkNew<vtkScalarBarWidget>
MakeScalarBarWidget(ScalarBarProperties& sbProperties,
vtkTextProperty* textProperty,
vtkTextProperty* labelTextProperty, vtkRenderer* ren,
vtkRenderWindowInteractor* iren)
{
vtkNew<vtkScalarBarActor> sbActor;
sbActor->SetLookupTable(sbProperties.lut);
sbActor->SetTitle(sbProperties.titleText.c_str());
sbActor->UnconstrainedFontSizeOn();
sbActor->SetNumberOfLabels(sbProperties.number_of_labels);
sbActor->SetTitleTextProperty(textProperty);
sbActor->SetLabelTextProperty(labelTextProperty);
sbActor->SetLabelFormat(sbProperties.labelFormat.c_str());
vtkNew<vtkScalarBarRepresentation> sbRep;
sbRep->EnforceNormalizedViewportBoundsOn();
sbRep->SetOrientation(sbProperties.orientation);
// Set the position.
sbRep->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
sbRep->GetPosition2Coordinate()->SetCoordinateSystemToNormalizedViewport();
if (sbProperties.orientation)
{
auto p1 = sbProperties.positionV["p"];
auto p2 = sbProperties.positionV["p2"];
sbRep->GetPositionCoordinate()->SetValue(p1.data());
sbRep->GetPosition2Coordinate()->SetValue(p2.data());
}
else
{
auto p1 = sbProperties.positionH["p"];
auto p2 = sbProperties.positionH["p2"];
sbRep->GetPositionCoordinate()->SetValue(p1.data());
sbRep->GetPosition2Coordinate()->SetValue(p2.data());
}
vtkNew<vtkScalarBarWidget> widget;
widget->SetRepresentation(sbRep);
widget->SetScalarBarActor(sbActor);
widget->SetDefaultRenderer(ren);
widget->SetInteractor(iren);
widget->EnabledOn();
return widget;
}
TTextPositions GetTextPositions(std::vector<std::string> const& names,
int const justification,
int const vertical_justification,
double const width, double const height)
{
// The gap between the left or right edge of the screen and the text.
auto dx = 0.02;
auto w = abs(width);
if (w > 0.96)
{
w = 0.96;
}
auto y0 = 0.01;
auto h = abs(height);
if (h > 0.9)
{
h = 0.9;
}
auto dy = h;
if (vertical_justification == VTK_TEXT_TOP)
{
y0 = 1.0 - (dy + y0);
}
if (vertical_justification == VTK_TEXT_CENTERED)
{
y0 = 0.5 - (dy / 2.0 + y0);
}
auto minmaxIt =
std::minmax_element(names.begin(), names.end(),
[](const std::string& a, const std::string& b) {
return a.length() < b.length();
});
// auto nameLenMin = minmaxIt.first->size();
auto nameLenMax = minmaxIt.second->size();
TTextPositions textPositions;
for (const auto& k : names)
{
auto sz = k.size();
auto delta_sz = w * sz / nameLenMax;
if (delta_sz > w)
{
delta_sz = w;
}
double x0 = 0;
if (justification == VTK_TEXT_CENTERED)
{
x0 = 0.5 - delta_sz / 2.0;
}
else if (justification == VTK_TEXT_RIGHT)
{
x0 = 1.0 - dx - delta_sz;
}
else
{
// Default is left justification.
x0 = dx;
}
textPositions[k] = {{"p", {x0, y0}}, {"p2", {delta_sz, dy}}};
// For testing.
// std::cout << k << std::endl;
// std::cout << " p: " << textPositions[k]["p"][0] << ", "
// << textPositions[k]["p"][1] << std::endl;
// std::cout << " p2: " << textPositions[k]["p2"][0] << ", "
// << textPositions[k]["p2"][1] << std::endl;
}
return textPositions;
}
std::string Title(const std::string& input)
{
std::string result = input;
bool capitalizeNext = true;
for (char& c : result)
{
if (std::isspace(static_cast<unsigned char>(c)))
{
capitalizeNext = true;
}
else if (capitalizeNext)
{
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
capitalizeNext = false;
}
else
{
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}
}
return result;
}
} // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(RescaleReverseLUT)
find_package(VTK COMPONENTS
CommonColor
CommonCore
FiltersCore
FiltersSources
InteractionStyle
RenderingAnnotation
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "RescaleReverseLUT: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(RescaleReverseLUT MACOSX_BUNDLE RescaleReverseLUT.cxx )
target_link_libraries(RescaleReverseLUT PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS RescaleReverseLUT
MODULES ${VTK_LIBRARIES}
)
Download and Build RescaleReverseLUT¶
Click here to download RescaleReverseLUT and its CMakeLists.txt file. Once the tarball RescaleReverseLUT.tar has been downloaded and extracted,
cd RescaleReverseLUT/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./RescaleReverseLUT
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.
