New gcode visualization library - Allow customization of range colors

This commit is contained in:
enricoturri1966 2024-01-11 08:51:03 +01:00 committed by Lukas Matena
parent 64b907e984
commit 7adaa32cd5
8 changed files with 250 additions and 218 deletions

View File

@ -11,8 +11,22 @@
namespace libvgcode {
static const Palette DEFAULT_RANGES_COLORS{ {
{ 11, 44, 122 }, // bluish
{ 19, 89, 133 },
{ 28, 136, 145 },
{ 4, 214, 15 },
{ 170, 242, 0 },
{ 252, 249, 3 },
{ 245, 206, 10 },
{ 227, 136, 32 },
{ 209, 104, 48 },
{ 194, 82, 60 },
{ 148, 38, 22 } // reddish
} };
//
// Helper class to interpolate between colors defined in RANGES_COLORS palette.
// Helper class to interpolate between colors defined in a palette.
// Interpolation can be done linearly or logarithmically.
// Usage:
// 1) Define an instance of ColorRange of the desired interpolation type
@ -31,54 +45,70 @@ public:
// Constructor
//
explicit ColorRange(EColorRangeType type = EColorRangeType::Linear);
//
// Use the passed value to update the range
//
void update(float value);
//
// Reset the range
// Call this method before reuse an instance of ColorRange
//
void reset();
//
// Return the type of this ColorRange
// Return the type of this ColorRange.
//
EColorRangeType get_type() const;
//
// Return the interpolated color at the given value
// Value is clamped to the range
// Return the palette used by this ColorRange.
// Default is DEFAULT_RANGES_COLORS
//
const Palette& get_palette() const;
//
// Set the palette to be used by this ColorRange.
// The given palette must contain at least two colors.
//
void set_palette(const Palette& palette);
//
// Return the interpolated color at the given value.
// Value is clamped to [get_range()[0]..get_range()[1]].
//
Color get_color_at(float value) const;
//
// Return the range of this ColorRange
// Return the range of this ColorRange.
// The range is detected during the call to Viewer::load().
// [0] -> min
// [1] -> max
//
const std::array<float, 2>& get_range() const;
float get_step_size() const;
//
// Return the values corresponding to the detected color bins of this ColorRange.
// The size of the returned vector can be:
// 1 - If only one value was detected while setting up this ColorRange.
// 2 - If only two values were detected while setting up this ColorRange.
// get_palette().size() - If more than two distinct values were detected while setting up this ColorRange.
//
std::vector<float> get_values() const;
static const ColorRange DUMMY_COLOR_RANGE;
private:
EColorRangeType m_type{ EColorRangeType::Linear };
//
// The palette used by this ColorRange
//
Palette m_palette;
//
// [0] = min
// [1] = max
//
std::array<float, 2> m_range{ FLT_MAX, -FLT_MAX };
//
// Count of different values passed to update()
//
size_t m_count{ 0 };
//
// Use the passed value to update the range.
//
void update(float value);
//
// Reset the range
// Call this method before reuse an instance of ColorRange.
//
void reset();
friend class ViewerImpl;
};
} // namespace libvgcode

View File

@ -50,6 +50,11 @@ using Mat4x4 = std::array<float, 16>;
//
using Color = std::array<uint8_t, 3>;
//
// Color palette
//
using Palette = std::vector<Color>;
//
// Axis aligned box in 3 dimensions
// [0] -> { min_x, min_y, min_z }
@ -196,25 +201,6 @@ static constexpr size_t BBOX_TYPES_COUNT = static_cast<size_t>(EBBoxType::COUNT)
//
static const Color DUMMY_COLOR{ 64, 64, 64 };
//
// Palette used to render moves by ranges
// EViewType: Height, Width, Speed, FanSpeed, Temperature, VolumetricFlowRate,
// LayerTimeLinear, LayerTimeLogarithmic
//
static const std::vector<Color> RANGES_COLORS{ {
{ 11, 44, 122 }, // bluish
{ 19, 89, 133 },
{ 28, 136, 145 },
{ 4, 214, 15 },
{ 170, 242, 0 },
{ 252, 249, 3 },
{ 245, 206, 10 },
{ 227, 136, 32 },
{ 209, 104, 48 },
{ 194, 82, 60 },
{ 148, 38, 22 } // reddish
} };
//
// Mapping from EMoveType to EOptionType
// Returns EOptionType::COUNT if the given move type does not correspond

View File

@ -264,8 +264,8 @@ public:
std::vector<float> get_layers_times(ETimeMode mode) const;
size_t get_tool_colors_count() const;
const std::vector<Color>& get_tool_colors() const;
void set_tool_colors(const std::vector<Color>& colors);
const Palette& get_tool_colors() const;
void set_tool_colors(const Palette& colors);
const Color& get_extrusion_role_color(EGCodeExtrusionRole role) const;
void set_extrusion_role_color(EGCodeExtrusionRole role, const Color& color);
@ -276,33 +276,33 @@ public:
void reset_default_options_colors();
//
// Get the color range for height.
// Get the color range for the given view type.
// Valid view types are:
// EViewType::Height
// EViewType::Width
// EViewType::Speed
// EViewType::FanSpeed
// EViewType::Temperature
// EViewType::VolumetricFlowRate
// EViewType::LayerTimeLinear
// EViewType::LayerTimeLogarithmic
//
const ColorRange& get_height_range() const;
const ColorRange& get_color_range(EViewType type) const;
//
// Get the color range for width.
// Set the palette for the color range corresponding to the given view type
// with the given value.
// Valid view types are:
// EViewType::Height
// EViewType::Width
// EViewType::Speed
// EViewType::FanSpeed
// EViewType::Temperature
// EViewType::VolumetricFlowRate
// EViewType::LayerTimeLinear
// EViewType::LayerTimeLogarithmic
//
const ColorRange& get_width_range() const;
//
// Get the color range for speed.
//
const ColorRange& get_speed_range() const;
//
// Get the color range for fan speed.
//
const ColorRange& get_fan_speed_range() const;
//
// Get the color range for temperature.
//
const ColorRange& get_temperature_range() const;
//
// Get the color range for volumetric range.
//
const ColorRange& get_volumetric_rate_range() const;
//
// Get the color range for the layer time range with the given type.
//
const ColorRange& get_layer_time_range(EColorRangeType type) const;
void set_color_range_palette(EViewType type, const Palette& palette);
//
// Get the radius, in mm, of the cylinders used to render the travel moves.
//

View File

@ -12,11 +12,106 @@ namespace libvgcode {
const ColorRange ColorRange::DUMMY_COLOR_RANGE = ColorRange();
static float get_step_size(const ColorRange& color_range)
{
const std::array<float, 2>& range = color_range.get_range();
const Palette& palette = color_range.get_palette();
switch (color_range.get_type())
{
default:
case EColorRangeType::Linear:
{
return (range[1] - range[0]) / (static_cast<float>(palette.size()) - 1.0f);
}
case EColorRangeType::Logarithmic:
{
return (range[0] != 0.0f) ? std::log(range[1] / range[0]) / (static_cast<float>(palette.size()) - 1.0f) : 0.0f;
}
}
}
ColorRange::ColorRange(EColorRangeType type)
: m_type(type)
, m_palette(DEFAULT_RANGES_COLORS)
{
}
EColorRangeType ColorRange::get_type() const
{
return m_type;
}
const Palette& ColorRange::get_palette() const
{
return m_palette;
}
void ColorRange::set_palette(const Palette& palette)
{
if (palette.size() > 1)
m_palette = palette;
}
Color ColorRange::get_color_at(float value) const
{
// Input value scaled to the colors range
float global_t = 0.0f;
value = std::clamp(value, m_range[0], m_range[1]);
const float step = get_step_size(*this);
if (step > 0.0f) {
if (m_type == EColorRangeType::Logarithmic) {
if (m_range[0] != 0.0f)
global_t = std::log(value / m_range[0]) / step;
}
else
global_t = (value - m_range[0]) / step;
}
const size_t color_max_idx = m_palette.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
const size_t color_low_idx = std::clamp<size_t>(static_cast<size_t>(global_t), 0, color_max_idx);
const size_t color_high_idx = std::clamp<size_t>(color_low_idx + 1, 0, color_max_idx);
// Interpolate between the low and high colors to find exactly which color the input value should get
return lerp(m_palette[color_low_idx], m_palette[color_high_idx], global_t - static_cast<float>(color_low_idx));
}
const std::array<float, 2>& ColorRange::get_range() const
{
return m_range;
}
std::vector<float> ColorRange::get_values() const
{
std::vector<float> ret;
if (m_count == 1) {
// single item use case
ret.emplace_back(m_range[0]);
}
else if (m_count == 2) {
// two items use case
ret.emplace_back(m_range[0]);
ret.emplace_back(m_range[1]);
}
else {
const float step_size = get_step_size(*this);
for (size_t i = 0; i < m_palette.size(); ++i) {
float value = 0.0f;
switch (m_type)
{
default:
case EColorRangeType::Linear: { value = m_range[0] + static_cast<float>(i) * step_size; break; }
case EColorRangeType::Logarithmic: { value = ::exp(::log(m_range[0]) + static_cast<float>(i) * step_size); break; }
}
ret.emplace_back(value);
}
}
return ret;
}
void ColorRange::update(float value)
{
if (value != m_range[0] && value != m_range[1])
@ -32,86 +127,5 @@ void ColorRange::reset()
m_count = 0;
}
EColorRangeType ColorRange::get_type() const
{
return m_type;
}
Color ColorRange::get_color_at(float value) const
{
// Input value scaled to the colors range
float global_t = 0.0f;
value = std::clamp(value, m_range[0], m_range[1]);
const float step = get_step_size();
if (step > 0.0f) {
if (m_type == EColorRangeType::Logarithmic) {
if (m_range[0] != 0.0f)
global_t = std::log(value / m_range[0]) / step;
}
else
global_t = (value - m_range[0]) / step;
}
const size_t color_max_idx = RANGES_COLORS.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
const size_t color_low_idx = std::clamp<size_t>(static_cast<size_t>(global_t), 0, color_max_idx);
const size_t color_high_idx = std::clamp<size_t>(color_low_idx + 1, 0, color_max_idx);
// Interpolate between the low and high colors to find exactly which color the input value should get
return lerp(RANGES_COLORS[color_low_idx], RANGES_COLORS[color_high_idx], global_t - static_cast<float>(color_low_idx));
}
const std::array<float, 2>& ColorRange::get_range() const
{
return m_range;
}
float ColorRange::get_step_size() const
{
switch (m_type)
{
default:
case EColorRangeType::Linear:
{
return (m_range[1] - m_range[0]) / (static_cast<float>(RANGES_COLORS.size()) - 1.0f);
}
case EColorRangeType::Logarithmic:
{
return (m_range[0] != 0.0f) ? std::log(m_range[1] / m_range[0]) / (static_cast<float>(RANGES_COLORS.size()) - 1.0f) : 0.0f;
}
}
}
std::vector<float> ColorRange::get_values() const
{
std::vector<float> ret;
if (m_count == 1) {
// single item use case
ret.emplace_back(m_range[0]);
}
else if (m_count == 2) {
// two items use case
ret.emplace_back(m_range[0]);
ret.emplace_back(m_range[1]);
}
else {
const float step_size = get_step_size();
for (size_t i = 0; i < RANGES_COLORS.size(); ++i) {
float value = 0.0f;
switch (m_type)
{
default:
case EColorRangeType::Linear: { value = m_range[0] + static_cast<float>(i) * step_size; break; }
case EColorRangeType::Logarithmic: { value = ::exp(::log(m_range[0]) + static_cast<float>(i) * step_size); break; }
}
ret.emplace_back(value);
}
}
return ret;
}
} // namespace libvgcode

View File

@ -262,12 +262,12 @@ size_t Viewer::get_tool_colors_count() const
return m_impl->get_tool_colors_count();
}
const std::vector<Color>& Viewer::get_tool_colors() const
const Palette& Viewer::get_tool_colors() const
{
return m_impl->get_tool_colors();
}
void Viewer::set_tool_colors(const std::vector<Color>& colors)
void Viewer::set_tool_colors(const Palette& colors)
{
m_impl->set_tool_colors(colors);
}
@ -302,39 +302,14 @@ void Viewer::reset_default_options_colors()
m_impl->reset_default_options_colors();
}
const ColorRange& Viewer::get_height_range() const
const ColorRange& Viewer::get_color_range(EViewType type) const
{
return m_impl->get_height_range();
return m_impl->get_color_range(type);
}
const ColorRange& Viewer::get_width_range() const
void Viewer::set_color_range_palette(EViewType type, const Palette& palette)
{
return m_impl->get_width_range();
}
const ColorRange& Viewer::get_speed_range() const
{
return m_impl->get_speed_range();
}
const ColorRange& Viewer::get_fan_speed_range() const
{
return m_impl->get_fan_speed_range();
}
const ColorRange& Viewer::get_temperature_range() const
{
return m_impl->get_temperature_range();
}
const ColorRange& Viewer::get_volumetric_rate_range() const
{
return m_impl->get_volumetric_rate_range();
}
const ColorRange& Viewer::get_layer_time_range(EColorRangeType type) const
{
return m_impl->get_layer_time_range(type);
m_impl->set_color_range_palette(type, palette);
}
float Viewer::get_travels_radius() const

View File

@ -931,7 +931,7 @@ Color ViewerImpl::get_vertex_color(const PathVertex& v) const
return DUMMY_COLOR;
}
void ViewerImpl::set_tool_colors(const std::vector<Color>& colors)
void ViewerImpl::set_tool_colors(const Palette& colors)
{
m_tool_colors = colors;
m_settings.update_colors = true;
@ -967,6 +967,39 @@ void ViewerImpl::set_option_color(EOptionType type, const Color& color)
}
}
const ColorRange& ViewerImpl::get_color_range(EViewType type) const
{
switch (type)
{
case EViewType::Height: { return m_height_range; }
case EViewType::Width: { return m_width_range; }
case EViewType::Speed: { return m_speed_range; }
case EViewType::FanSpeed: { return m_fan_speed_range; }
case EViewType::Temperature: { return m_temperature_range; }
case EViewType::VolumetricFlowRate: { return m_volumetric_rate_range; }
case EViewType::LayerTimeLinear: { return m_layer_time_range[0]; }
case EViewType::LayerTimeLogarithmic: { return m_layer_time_range[1]; }
default: { return ColorRange::DUMMY_COLOR_RANGE; }
}
}
void ViewerImpl::set_color_range_palette(EViewType type, const Palette& palette)
{
switch (type)
{
case EViewType::Height: { m_height_range.set_palette(palette); }
case EViewType::Width: { m_width_range.set_palette(palette); }
case EViewType::Speed: { m_speed_range.set_palette(palette); }
case EViewType::FanSpeed: { m_fan_speed_range.set_palette(palette); }
case EViewType::Temperature: { m_temperature_range.set_palette(palette); }
case EViewType::VolumetricFlowRate: { m_volumetric_rate_range.set_palette(palette); }
case EViewType::LayerTimeLinear: { m_layer_time_range[0].set_palette(palette); }
case EViewType::LayerTimeLogarithmic: { m_layer_time_range[1].set_palette(palette); }
default: { break; }
}
m_settings.update_colors = true;
}
void ViewerImpl::set_travels_radius(float radius)
{
m_travels_radius = std::clamp(radius, 0.05f, 0.5f);

View File

@ -136,8 +136,8 @@ public:
std::vector<float> get_layers_times(ETimeMode mode) const { return m_layers.get_times(mode); }
size_t get_tool_colors_count() const { return m_tool_colors.size(); }
const std::vector<Color>& get_tool_colors() const { return m_tool_colors; }
void set_tool_colors(const std::vector<Color>& colors);
const Palette& get_tool_colors() const { return m_tool_colors; }
void set_tool_colors(const Palette& colors);
const Color& get_extrusion_role_color(EGCodeExtrusionRole role) const;
void set_extrusion_role_color(EGCodeExtrusionRole role, const Color& color);
@ -147,16 +147,8 @@ public:
void set_option_color(EOptionType type, const Color& color);
void reset_default_options_colors() { m_options_colors = DEFAULT_OPTIONS_COLORS; }
const ColorRange& get_height_range() const { return m_height_range; }
const ColorRange& get_width_range() const { return m_width_range; }
const ColorRange& get_speed_range() const { return m_speed_range; }
const ColorRange& get_fan_speed_range() const { return m_fan_speed_range; }
const ColorRange& get_temperature_range() const { return m_temperature_range; }
const ColorRange& get_volumetric_rate_range() const { return m_volumetric_rate_range; }
const ColorRange& get_layer_time_range(EColorRangeType type) const {
return (static_cast<size_t>(type) < m_layer_time_range.size()) ?
m_layer_time_range[static_cast<size_t>(type)] : ColorRange::DUMMY_COLOR_RANGE;
}
const ColorRange& get_color_range(EViewType type) const;
void set_color_range_palette(EViewType type, const Palette& palette);
float get_travels_radius() const { return m_travels_radius; }
void set_travels_radius(float radius);
@ -255,7 +247,7 @@ private:
std::array<ColorRange, COLOR_RANGE_TYPES_COUNT> m_layer_time_range{
ColorRange(EColorRangeType::Linear), ColorRange(EColorRangeType::Logarithmic)
};
std::vector<Color> m_tool_colors;
Palette m_tool_colors;
//
// OpenGL shader ids

View File

@ -3936,14 +3936,14 @@ void GCodeViewer::render_toolpaths()
imgui.text(buf);
};
add_range_property_row("height range", m_viewer.get_height_range().get_range());
add_range_property_row("width range", m_viewer.get_width_range().get_range());
add_range_property_row("speed range", m_viewer.get_speed_range().get_range());
add_range_property_row("fan speed range", m_viewer.get_fan_speed_range().get_range());
add_range_property_row("temperature range", m_viewer.get_temperature_range().get_range());
add_range_property_row("volumetric rate range", m_viewer.get_volumetric_rate_range().get_range());
add_range_property_row("layer time linear range", m_viewer.get_layer_time_range(libvgcode::EColorRangeType::Linear).get_range());
add_range_property_row("layer time logarithmic range", m_viewer.get_layer_time_range(libvgcode::EColorRangeType::Logarithmic).get_range());
add_range_property_row("height range", m_viewer.get_color_range(libvgcode::EViewType::Height).get_range());
add_range_property_row("width range", m_viewer.get_color_range(libvgcode::EViewType::Width).get_range());
add_range_property_row("speed range", m_viewer.get_color_range(libvgcode::EViewType::Speed).get_range());
add_range_property_row("fan speed range", m_viewer.get_color_range(libvgcode::EViewType::FanSpeed).get_range());
add_range_property_row("temperature range", m_viewer.get_color_range(libvgcode::EViewType::Temperature).get_range());
add_range_property_row("volumetric rate range", m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate).get_range());
add_range_property_row("layer time linear range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear).get_range());
add_range_property_row("layer time logarithmic range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic).get_range());
ImGui::EndTable();
@ -4538,14 +4538,15 @@ void GCodeViewer::render_legend(float& legend_height)
#if ENABLE_NEW_GCODE_VIEWER
auto append_range = [append_item](const libvgcode::ColorRange& range, unsigned int decimals) {
auto append_range_item = [append_item, &range](int i, float value, unsigned int decimals) {
#else
auto append_range = [append_item](const Extrusions::Range& range, unsigned int decimals) {
#endif // ENABLE_NEW_GCODE_VIEWER
auto append_range_item = [append_item](int i, float value, unsigned int decimals) {
#endif // ENABLE_NEW_GCODE_VIEWER
char buf[1024];
::sprintf(buf, "%.*f", decimals, value);
#if ENABLE_NEW_GCODE_VIEWER
append_item(EItemType::Rect, libvgcode::convert(libvgcode::RANGES_COLORS[i]), buf);
append_item(EItemType::Rect, libvgcode::convert(range.get_palette()[i]), buf);
#else
append_item(EItemType::Rect, Range_Colors[i], buf);
#endif // ENABLE_NEW_GCODE_VIEWER
@ -4558,11 +4559,11 @@ void GCodeViewer::render_legend(float& legend_height)
append_range_item(0, values.front(), decimals);
else if (values.size() == 2) {
// two items use case
append_range_item(static_cast<int>(libvgcode::RANGES_COLORS.size()) - 1, values.back(), decimals);
append_range_item(static_cast<int>(range.get_palette().size()) - 1, values.back(), decimals);
append_range_item(0, values.front(), decimals);
}
else {
for (int i = static_cast<int>(libvgcode::RANGES_COLORS.size()) - 1; i >= 0; --i) {
for (int i = static_cast<int>(range.get_palette().size()) - 1; i >= 0; --i) {
append_range_item(i, values[i], decimals);
}
}
@ -4586,15 +4587,16 @@ void GCodeViewer::render_legend(float& legend_height)
#if ENABLE_NEW_GCODE_VIEWER
auto append_time_range = [append_item](const libvgcode::ColorRange& range) {
auto append_range_item = [append_item, &range](int i, float value) {
#else
auto append_time_range = [append_item](const Extrusions::Range& range, Extrusions::Range::EType type) {
#endif // ENABLE_NEW_GCODE_VIEWER
auto append_range_item = [append_item](int i, float value) {
#endif // ENABLE_NEW_GCODE_VIEWER
std::string str_value = get_time_dhms(value);
if (str_value == "0s")
str_value = "< 1s";
#if ENABLE_NEW_GCODE_VIEWER
append_item(EItemType::Rect, libvgcode::convert(libvgcode::RANGES_COLORS[i]), str_value);
append_item(EItemType::Rect, libvgcode::convert(range.get_palette()[i]), str_value);
#else
append_item(EItemType::Rect, Range_Colors[i], str_value);
#endif // ENABLE_NEW_GCODE_VIEWER
@ -4607,11 +4609,11 @@ void GCodeViewer::render_legend(float& legend_height)
append_range_item(0, values.front());
else if (values.size() == 2) {
// two items use case
append_range_item(static_cast<int>(libvgcode::RANGES_COLORS.size()) - 1, values.back());
append_range_item(static_cast<int>(range.get_palette().size()) - 1, values.back());
append_range_item(0, values.front());
}
else {
for (int i = static_cast<int>(libvgcode::RANGES_COLORS.size()) - 1; i >= 0; --i) {
for (int i = static_cast<int>(range.get_palette().size()) - 1; i >= 0; --i) {
append_range_item(i, values[i]);
}
}
@ -5014,14 +5016,14 @@ void GCodeViewer::render_legend(float& legend_height)
break;
}
#if ENABLE_NEW_GCODE_VIEWER
case libvgcode::EViewType::Height: { append_range(m_viewer.get_height_range(), 3); break; }
case libvgcode::EViewType::Width: { append_range(m_viewer.get_width_range(), 3); break; }
case libvgcode::EViewType::Speed: { append_range(m_viewer.get_speed_range(), 1); break; }
case libvgcode::EViewType::FanSpeed: { append_range(m_viewer.get_fan_speed_range(), 0); break; }
case libvgcode::EViewType::Temperature: { append_range(m_viewer.get_temperature_range(), 0); break; }
case libvgcode::EViewType::VolumetricFlowRate: { append_range(m_viewer.get_volumetric_rate_range(), 3); break; }
case libvgcode::EViewType::LayerTimeLinear: { append_time_range(m_viewer.get_layer_time_range(libvgcode::EColorRangeType::Linear)); break; }
case libvgcode::EViewType::LayerTimeLogarithmic: { append_time_range(m_viewer.get_layer_time_range(libvgcode::EColorRangeType::Logarithmic)); break; }
case libvgcode::EViewType::Height: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Height), 3); break; }
case libvgcode::EViewType::Width: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Width), 3); break; }
case libvgcode::EViewType::Speed: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Speed), 1); break; }
case libvgcode::EViewType::FanSpeed: { append_range(m_viewer.get_color_range(libvgcode::EViewType::FanSpeed), 0); break; }
case libvgcode::EViewType::Temperature: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Temperature), 0); break; }
case libvgcode::EViewType::VolumetricFlowRate: { append_range(m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate), 3); break; }
case libvgcode::EViewType::LayerTimeLinear: { append_time_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear)); break; }
case libvgcode::EViewType::LayerTimeLogarithmic: { append_time_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic)); break; }
case libvgcode::EViewType::Tool: {
// shows only extruders actually used
const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();