mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-05 23:05:10 +08:00
Merge remote-tracking branch 'foxox/feature/ScaleSpeedLegendToVisible2'
This commit is contained in:
commit
6be4b3865b
@ -978,7 +978,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||||||
float volumetric_rate = FLT_MAX;
|
float volumetric_rate = FLT_MAX;
|
||||||
GCodePreviewData::Range height_range;
|
GCodePreviewData::Range height_range;
|
||||||
GCodePreviewData::Range width_range;
|
GCodePreviewData::Range width_range;
|
||||||
GCodePreviewData::Range feedrate_range;
|
GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
|
||||||
GCodePreviewData::Range volumetric_rate_range;
|
GCodePreviewData::Range volumetric_rate_range;
|
||||||
GCodePreviewData::Range fan_speed_range;
|
GCodePreviewData::Range fan_speed_range;
|
||||||
|
|
||||||
@ -1013,7 +1013,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||||||
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
|
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
|
||||||
height_range.update_from(move.data.height);
|
height_range.update_from(move.data.height);
|
||||||
width_range.update_from(move.data.width);
|
width_range.update_from(move.data.width);
|
||||||
feedrate_range.update_from(move.data.feedrate);
|
feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION);
|
||||||
volumetric_rate_range.update_from(volumetric_rate);
|
volumetric_rate_range.update_from(volumetric_rate);
|
||||||
fan_speed_range.update_from(move.data.fan_speed);
|
fan_speed_range.update_from(move.data.fan_speed);
|
||||||
}
|
}
|
||||||
@ -1066,7 +1066,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
|||||||
|
|
||||||
GCodePreviewData::Range height_range;
|
GCodePreviewData::Range height_range;
|
||||||
GCodePreviewData::Range width_range;
|
GCodePreviewData::Range width_range;
|
||||||
GCodePreviewData::Range feedrate_range;
|
GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
|
||||||
|
|
||||||
// to avoid to call the callback too often
|
// to avoid to call the callback too often
|
||||||
unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1);
|
unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1);
|
||||||
@ -1106,7 +1106,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
|||||||
extruder_id = move.data.extruder_id;
|
extruder_id = move.data.extruder_id;
|
||||||
height_range.update_from(move.data.height);
|
height_range.update_from(move.data.height);
|
||||||
width_range.update_from(move.data.width);
|
width_range.update_from(move.data.width);
|
||||||
feedrate_range.update_from(move.data.feedrate);
|
feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::TRAVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// store last polyline
|
// store last polyline
|
||||||
|
@ -11,9 +11,7 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
const GCodePreviewData::Color GCodePreviewData::Color::Dummy(0.0f, 0.0f, 0.0f, 0.0f);
|
std::vector<unsigned char> Color::as_bytes() const
|
||||||
|
|
||||||
std::vector<unsigned char> GCodePreviewData::Color::as_bytes() const
|
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> ret;
|
std::vector<unsigned char> ret;
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
@ -38,20 +36,6 @@ GCodePreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, f
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const GCodePreviewData::Color GCodePreviewData::Range::Default_Colors[Colors_Count] =
|
|
||||||
{
|
|
||||||
Color(0.043f, 0.173f, 0.478f, 1.0f),
|
|
||||||
Color(0.075f, 0.349f, 0.522f, 1.0f),
|
|
||||||
Color(0.110f, 0.533f, 0.569f, 1.0f),
|
|
||||||
Color(0.016f, 0.839f, 0.059f, 1.0f),
|
|
||||||
Color(0.667f, 0.949f, 0.000f, 1.0f),
|
|
||||||
Color(0.988f, 0.975f, 0.012f, 1.0f),
|
|
||||||
Color(0.961f, 0.808f, 0.039f, 1.0f),
|
|
||||||
Color(0.890f, 0.533f, 0.125f, 1.0f),
|
|
||||||
Color(0.820f, 0.408f, 0.188f, 1.0f),
|
|
||||||
Color(0.761f, 0.322f, 0.235f, 1.0f)
|
|
||||||
};
|
|
||||||
|
|
||||||
GCodePreviewData::Range::Range()
|
GCodePreviewData::Range::Range()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
@ -59,54 +43,52 @@ GCodePreviewData::Range::Range()
|
|||||||
|
|
||||||
void GCodePreviewData::Range::reset()
|
void GCodePreviewData::Range::reset()
|
||||||
{
|
{
|
||||||
min = FLT_MAX;
|
min_val = FLT_MAX;
|
||||||
max = -FLT_MAX;
|
max_val = -FLT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCodePreviewData::Range::empty() const
|
bool GCodePreviewData::Range::empty() const
|
||||||
{
|
{
|
||||||
return min == max;
|
return min_val >= max_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodePreviewData::Range::update_from(float value)
|
void GCodePreviewData::Range::update_from(float value)
|
||||||
{
|
{
|
||||||
min = std::min(min, value);
|
min_val = std::min(min_val, value);
|
||||||
max = std::max(max, value);
|
max_val = std::max(max_val, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodePreviewData::Range::update_from(const Range& other)
|
void GCodePreviewData::Range::update_from(const RangeBase& other)
|
||||||
{
|
{
|
||||||
min = std::min(min, other.min);
|
min_val = std::min(min_val, other.min());
|
||||||
max = std::max(max, other.max);
|
max_val = std::max(max_val, other.max());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodePreviewData::Range::set_from(const Range& other)
|
float GCodePreviewData::RangeBase::step_size() const
|
||||||
{
|
{
|
||||||
min = other.min;
|
return (max() - min()) / static_cast<float>(range_rainbow_colors.size() - 1);
|
||||||
max = other.max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float GCodePreviewData::Range::step_size() const
|
Color GCodePreviewData::RangeBase::get_color_at(float value) const
|
||||||
{
|
|
||||||
return (max - min) / (float)(Colors_Count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
|
|
||||||
{
|
{
|
||||||
if (empty())
|
if (empty())
|
||||||
return Color::Dummy;
|
return Color{};
|
||||||
|
|
||||||
float global_t = (value - min) / step_size();
|
// Input value scaled to the color range
|
||||||
|
const float global_t = std::max(0.0f, value - min()) / step_size(); // lower limit of 0.0f
|
||||||
|
|
||||||
|
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
|
||||||
|
|
||||||
unsigned int low = (unsigned int)global_t;
|
// Compute the two colors just below (low) and above (high) the input value
|
||||||
unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1);
|
const std::size_t color_low_idx = clamp(std::size_t{0}, color_max_idx, static_cast<std::size_t>(global_t));
|
||||||
|
const std::size_t color_high_idx = clamp(std::size_t{0}, color_max_idx, color_low_idx + 1);
|
||||||
|
const Color color_low = range_rainbow_colors[color_low_idx];
|
||||||
|
const Color color_high = range_rainbow_colors[color_high_idx];
|
||||||
|
|
||||||
Color color_low = colors[low];
|
// Compute how far the value is between the low and high colors so that they can be interpolated
|
||||||
Color color_high = colors[high];
|
const float local_t = std::min(global_t - static_cast<float>(color_low_idx), 1.0f); // upper limit of 1.0f
|
||||||
|
|
||||||
float local_t = global_t - (float)low;
|
// Interpolate between the low and high colors in RGB space to find exactly which color the input value should get
|
||||||
|
|
||||||
// interpolate in RGB space
|
|
||||||
Color ret;
|
Color ret;
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
@ -115,13 +97,23 @@ GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const GCodePreviewData::Color& color)
|
float GCodePreviewData::Range::min() const
|
||||||
|
{
|
||||||
|
return min_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GCodePreviewData::Range::max() const
|
||||||
|
{
|
||||||
|
return max_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const Color& color)
|
||||||
: text(text)
|
: text(text)
|
||||||
, color(color)
|
, color(color)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const GCodePreviewData::Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
|
const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
|
||||||
{
|
{
|
||||||
Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone
|
Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone
|
||||||
Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter
|
Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter
|
||||||
@ -180,7 +172,7 @@ size_t GCodePreviewData::Extrusion::memory_used() const
|
|||||||
|
|
||||||
const float GCodePreviewData::Travel::Default_Width = 0.075f;
|
const float GCodePreviewData::Travel::Default_Width = 0.075f;
|
||||||
const float GCodePreviewData::Travel::Default_Height = 0.075f;
|
const float GCodePreviewData::Travel::Default_Height = 0.075f;
|
||||||
const GCodePreviewData::Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
|
const Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
|
||||||
{
|
{
|
||||||
Color(0.0f, 0.0f, 0.75f, 1.0f), // Move
|
Color(0.0f, 0.0f, 0.75f, 1.0f), // Move
|
||||||
Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude
|
Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude
|
||||||
@ -206,7 +198,7 @@ size_t GCodePreviewData::Travel::memory_used() const
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
const Color GCodePreviewData::Retraction::Default_Color = Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
|
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
|
||||||
: position(position)
|
: position(position)
|
||||||
@ -238,17 +230,15 @@ GCodePreviewData::GCodePreviewData()
|
|||||||
|
|
||||||
void GCodePreviewData::set_default()
|
void GCodePreviewData::set_default()
|
||||||
{
|
{
|
||||||
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
|
||||||
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
|
||||||
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
|
||||||
::memcpy((void*)ranges.fan_speed.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
|
||||||
::memcpy((void*)ranges.volumetric_rate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
|
||||||
|
|
||||||
extrusion.set_default();
|
extrusion.set_default();
|
||||||
travel.set_default();
|
travel.set_default();
|
||||||
retraction.set_default();
|
retraction.set_default();
|
||||||
unretraction.set_default();
|
unretraction.set_default();
|
||||||
shell.set_default();
|
shell.set_default();
|
||||||
|
|
||||||
|
// Configure the color range for feedrate to match the default for travels and to enable extrusions since they are always visible
|
||||||
|
ranges.feedrate.set_mode(FeedrateKind::TRAVEL, travel.is_visible);
|
||||||
|
ranges.feedrate.set_mode(FeedrateKind::EXTRUSION, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodePreviewData::reset()
|
void GCodePreviewData::reset()
|
||||||
@ -268,32 +258,32 @@ bool GCodePreviewData::empty() const
|
|||||||
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
|
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
|
Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
|
||||||
{
|
{
|
||||||
return extrusion.role_colors[role];
|
return extrusion.role_colors[role];
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const
|
Color GCodePreviewData::get_height_color(float height) const
|
||||||
{
|
{
|
||||||
return ranges.height.get_color_at(height);
|
return ranges.height.get_color_at(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_width_color(float width) const
|
Color GCodePreviewData::get_width_color(float width) const
|
||||||
{
|
{
|
||||||
return ranges.width.get_color_at(width);
|
return ranges.width.get_color_at(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const
|
Color GCodePreviewData::get_feedrate_color(float feedrate) const
|
||||||
{
|
{
|
||||||
return ranges.feedrate.get_color_at(feedrate);
|
return ranges.feedrate.get_color_at(feedrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
|
Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
|
||||||
{
|
{
|
||||||
return ranges.fan_speed.get_color_at(fan_speed);
|
return ranges.fan_speed.get_color_at(fan_speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color GCodePreviewData::get_volumetric_rate_color(float rate) const
|
Color GCodePreviewData::get_volumetric_rate_color(float rate) const
|
||||||
{
|
{
|
||||||
return ranges.volumetric_rate.get_color_at(rate);
|
return ranges.volumetric_rate.get_color_at(rate);
|
||||||
}
|
}
|
||||||
@ -312,7 +302,7 @@ void GCodePreviewData::set_extrusion_role_color(const std::string& role_name, fl
|
|||||||
|
|
||||||
void GCodePreviewData::set_extrusion_paths_colors(const std::vector<std::string>& colors)
|
void GCodePreviewData::set_extrusion_paths_colors(const std::vector<std::string>& colors)
|
||||||
{
|
{
|
||||||
unsigned int size = (unsigned int)colors.size();
|
unsigned int size = (unsigned int)range_rainbow_colors.size();
|
||||||
|
|
||||||
if (size % 2 != 0)
|
if (size % 2 != 0)
|
||||||
return;
|
return;
|
||||||
@ -384,16 +374,16 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
|||||||
{
|
{
|
||||||
struct Helper
|
struct Helper
|
||||||
{
|
{
|
||||||
static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
|
static void FillListFromRange(LegendItemsList& list, const RangeBase& range, unsigned int decimals, float scale_factor)
|
||||||
{
|
{
|
||||||
list.reserve(Range::Colors_Count);
|
list.reserve(range_rainbow_colors.size());
|
||||||
|
|
||||||
float step = range.step_size();
|
float step = range.step_size();
|
||||||
for (int i = Range::Colors_Count - 1; i >= 0; --i)
|
for (int i = static_cast<int>(range_rainbow_colors.size()) - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step));
|
sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step));
|
||||||
list.emplace_back(buf, range.colors[i]);
|
list.emplace_back(buf, range_rainbow_colors[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -446,8 +436,8 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
|||||||
items.reserve(tools_colors_count);
|
items.reserve(tools_colors_count);
|
||||||
for (unsigned int i = 0; i < tools_colors_count; ++i)
|
for (unsigned int i = 0; i < tools_colors_count; ++i)
|
||||||
{
|
{
|
||||||
GCodePreviewData::Color color;
|
Color color;
|
||||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||||
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
|
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +450,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
|||||||
if (color_print_cnt == 1) // means "Default print color"
|
if (color_print_cnt == 1) // means "Default print color"
|
||||||
{
|
{
|
||||||
Color color;
|
Color color;
|
||||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data()), 4 * sizeof(float));
|
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data()), 4 * sizeof(float));
|
||||||
|
|
||||||
items.emplace_back(cp_items[0], color);
|
items.emplace_back(cp_items[0], color);
|
||||||
break;
|
break;
|
||||||
@ -472,7 +462,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
|||||||
for (int i = 0 ; i < color_print_cnt; ++i)
|
for (int i = 0 ; i < color_print_cnt; ++i)
|
||||||
{
|
{
|
||||||
Color color;
|
Color color;
|
||||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||||
|
|
||||||
items.emplace_back(cp_items[i], color);
|
items.emplace_back(cp_items[i], color);
|
||||||
}
|
}
|
||||||
@ -496,23 +486,23 @@ size_t GCodePreviewData::memory_used() const
|
|||||||
sizeof(shell) + sizeof(ranges);
|
sizeof(shell) + sizeof(ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& GCodePreviewData::ColorPrintColors()
|
const std::vector<std::string>& ColorPrintColors()
|
||||||
{
|
{
|
||||||
static std::vector<std::string> color_print = {"#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6"};
|
static std::vector<std::string> color_print = {"#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6"};
|
||||||
return color_print;
|
return color_print;
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2)
|
Color operator + (const Color& c1, const Color& c2)
|
||||||
{
|
{
|
||||||
return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]),
|
return Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]),
|
||||||
clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]),
|
clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]),
|
||||||
clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]),
|
clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]),
|
||||||
clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3]));
|
clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3]));
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color)
|
Color operator * (float f, const Color& color)
|
||||||
{
|
{
|
||||||
return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
|
return Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
|
||||||
clamp(0.0f, 1.0f, f * color.rgba[1]),
|
clamp(0.0f, 1.0f, f * color.rgba[1]),
|
||||||
clamp(0.0f, 1.0f, f * color.rgba[2]),
|
clamp(0.0f, 1.0f, f * color.rgba[2]),
|
||||||
clamp(0.0f, 1.0f, f * color.rgba[3]));
|
clamp(0.0f, 1.0f, f * color.rgba[3]));
|
||||||
|
@ -5,43 +5,188 @@
|
|||||||
#include "../ExtrusionEntity.hpp"
|
#include "../ExtrusionEntity.hpp"
|
||||||
#include "../Point.hpp"
|
#include "../Point.hpp"
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
// Represents an RGBA color
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
std::array<float,4> rgba;
|
||||||
|
|
||||||
|
Color(const float *argba)
|
||||||
|
{
|
||||||
|
memcpy(this->rgba.data(), argba, sizeof(float) * 4);
|
||||||
|
}
|
||||||
|
constexpr Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) : rgba{r,g,b,a}
|
||||||
|
{
|
||||||
|
// Intentionally empty
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> as_bytes() const;
|
||||||
|
};
|
||||||
|
Color operator + (const Color& c1, const Color& c2);
|
||||||
|
Color operator * (float f, const Color& color);
|
||||||
|
|
||||||
|
// Default colors for Ranges
|
||||||
|
constexpr std::array<Color, 10> range_rainbow_colors{
|
||||||
|
Color{0.043f, 0.173f, 0.478f, 1.0f},
|
||||||
|
Color{0.075f, 0.349f, 0.522f, 1.0f},
|
||||||
|
Color{0.110f, 0.533f, 0.569f, 1.0f},
|
||||||
|
Color{0.016f, 0.839f, 0.059f, 1.0f},
|
||||||
|
Color{0.667f, 0.949f, 0.000f, 1.0f},
|
||||||
|
Color{0.988f, 0.975f, 0.012f, 1.0f},
|
||||||
|
Color{0.961f, 0.808f, 0.039f, 1.0f},
|
||||||
|
Color{0.890f, 0.533f, 0.125f, 1.0f},
|
||||||
|
Color{0.820f, 0.408f, 0.188f, 1.0f},
|
||||||
|
Color{0.761f, 0.322f, 0.235f, 1.0f}};
|
||||||
|
|
||||||
class GCodePreviewData
|
class GCodePreviewData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Color
|
|
||||||
|
// Color mapping to convert a float into a smooth rainbow of 10 colors.
|
||||||
|
class RangeBase
|
||||||
{
|
{
|
||||||
float rgba[4];
|
public:
|
||||||
|
|
||||||
Color(const float *argba) { memcpy(this->rgba, argba, sizeof(float) * 4); }
|
virtual void reset() = 0;
|
||||||
Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a; }
|
virtual bool empty() const = 0;
|
||||||
|
virtual float min() const = 0;
|
||||||
std::vector<unsigned char> as_bytes() const;
|
virtual float max() const = 0;
|
||||||
|
|
||||||
static const Color Dummy;
|
// Gets the step size using min(), max() and colors
|
||||||
|
float step_size() const;
|
||||||
|
|
||||||
|
// Gets the color at a value using colors, min(), and max()
|
||||||
|
Color get_color_at(float value) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Color mapping from a <min, max> range into a smooth rainbow of 10 colors.
|
// Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
|
||||||
struct Range
|
class Range : public RangeBase
|
||||||
{
|
{
|
||||||
static const unsigned int Colors_Count = 10;
|
public:
|
||||||
static const Color Default_Colors[Colors_Count];
|
|
||||||
|
|
||||||
Color colors[Colors_Count];
|
|
||||||
float min;
|
|
||||||
float max;
|
|
||||||
|
|
||||||
Range();
|
Range();
|
||||||
|
|
||||||
void reset();
|
// RangeBase Overrides
|
||||||
bool empty() const;
|
void reset() override;
|
||||||
|
bool empty() const override;
|
||||||
|
float min() const override;
|
||||||
|
float max() const override;
|
||||||
|
|
||||||
|
// Range-specific methods
|
||||||
void update_from(float value);
|
void update_from(float value);
|
||||||
void update_from(const Range& other);
|
void update_from(const RangeBase& other);
|
||||||
void set_from(const Range& other);
|
|
||||||
float step_size() const;
|
|
||||||
|
|
||||||
Color get_color_at(float value) const;
|
private:
|
||||||
|
float min_val;
|
||||||
|
float max_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Like Range, but stores multiple ranges internally that are used depending on mode.
|
||||||
|
// Template param EnumRangeType must be an enum with values for each type of range that needs to be tracked in this MultiRange.
|
||||||
|
// The last enum value should be num_values. The numerical values of all enum values should range from 0 to num_values.
|
||||||
|
template <typename EnumRangeType>
|
||||||
|
class MultiRange : public RangeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void reset() override
|
||||||
|
{
|
||||||
|
bounds = decltype(bounds){};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const override
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||||
|
{
|
||||||
|
if (bounds[i].min != bounds[i].max)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float min() const override
|
||||||
|
{
|
||||||
|
float min = FLT_MAX;
|
||||||
|
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||||
|
{
|
||||||
|
// Only use bounds[i] if the current mode includes it
|
||||||
|
if (mode.test(i))
|
||||||
|
{
|
||||||
|
min = std::min(min, bounds[i].min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
float max() const override
|
||||||
|
{
|
||||||
|
float max = -FLT_MAX;
|
||||||
|
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||||
|
{
|
||||||
|
// Only use bounds[i] if the current mode includes it
|
||||||
|
if (mode.test(i))
|
||||||
|
{
|
||||||
|
max = std::max(max, bounds[i].max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_from(const float value, EnumRangeType range_type_value)
|
||||||
|
{
|
||||||
|
bounds[static_cast<std::size_t>(range_type_value)].update_from(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_from(const MultiRange& other)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||||
|
{
|
||||||
|
bounds[i].update_from(other.bounds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_mode(const EnumRangeType range_type_value, const bool enable)
|
||||||
|
{
|
||||||
|
mode.set(static_cast<std::size_t>(range_type_value), enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Interval bounds
|
||||||
|
struct Bounds
|
||||||
|
{
|
||||||
|
float min{FLT_MAX};
|
||||||
|
float max{-FLT_MAX};
|
||||||
|
void update_from(const float value)
|
||||||
|
{
|
||||||
|
min = std::min(min, value);
|
||||||
|
max = std::max(max, value);
|
||||||
|
}
|
||||||
|
void update_from(const Bounds other_bounds)
|
||||||
|
{
|
||||||
|
min = std::min(min, other_bounds.min);
|
||||||
|
max = std::max(max, other_bounds.max);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<Bounds, static_cast<std::size_t>(EnumRangeType::num_values)> bounds;
|
||||||
|
std::bitset<static_cast<std::size_t>(EnumRangeType::num_values)> mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enum distinguishing different kinds of feedrate data
|
||||||
|
enum class FeedrateKind
|
||||||
|
{
|
||||||
|
EXTRUSION = 0, // values must go from 0 up to num_values
|
||||||
|
TRAVEL,
|
||||||
|
num_values //must be last in the list of values
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ranges
|
struct Ranges
|
||||||
@ -51,7 +196,7 @@ public:
|
|||||||
// Color mapping by extrusion width.
|
// Color mapping by extrusion width.
|
||||||
Range width;
|
Range width;
|
||||||
// Color mapping by feedrate.
|
// Color mapping by feedrate.
|
||||||
Range feedrate;
|
MultiRange<FeedrateKind> feedrate;
|
||||||
// Color mapping by fan speed.
|
// Color mapping by fan speed.
|
||||||
Range fan_speed;
|
Range fan_speed;
|
||||||
// Color mapping by volumetric extrusion rate.
|
// Color mapping by volumetric extrusion rate.
|
||||||
@ -245,9 +390,6 @@ public:
|
|||||||
static const std::vector<std::string>& ColorPrintColors();
|
static const std::vector<std::string>& ColorPrintColors();
|
||||||
};
|
};
|
||||||
|
|
||||||
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2);
|
|
||||||
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color);
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif /* slic3r_GCode_PreviewData_hpp_ */
|
#endif /* slic3r_GCode_PreviewData_hpp_ */
|
||||||
|
@ -2427,7 +2427,7 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio
|
|||||||
|
|
||||||
volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size());
|
volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size());
|
||||||
|
|
||||||
GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba, VERTEX_BUFFER_RESERVE_SIZE);
|
GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba.data(), VERTEX_BUFFER_RESERVE_SIZE);
|
||||||
|
|
||||||
GCodePreviewData::Retraction::PositionsList copy(retractions.positions);
|
GCodePreviewData::Retraction::PositionsList copy(retractions.positions);
|
||||||
std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); });
|
std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); });
|
||||||
@ -5863,7 +5863,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GCodePreviewData::Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
|
static Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
|
||||||
{
|
{
|
||||||
switch (data.extrusion.view_type)
|
switch (data.extrusion.view_type)
|
||||||
{
|
{
|
||||||
@ -5881,8 +5881,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||||||
return data.get_volumetric_rate_color(value);
|
return data.get_volumetric_rate_color(value);
|
||||||
case GCodePreviewData::Extrusion::Tool:
|
case GCodePreviewData::Extrusion::Tool:
|
||||||
{
|
{
|
||||||
GCodePreviewData::Color color;
|
Color color;
|
||||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
|
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
case GCodePreviewData::Extrusion::ColorPrint:
|
case GCodePreviewData::Extrusion::ColorPrint:
|
||||||
@ -5890,16 +5890,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||||||
int color_cnt = (int)tool_colors.size() / 4;
|
int color_cnt = (int)tool_colors.size() / 4;
|
||||||
int val = value > color_cnt ? color_cnt - 1 : value;
|
int val = value > color_cnt ? color_cnt - 1 : value;
|
||||||
|
|
||||||
GCodePreviewData::Color color;
|
Color color;
|
||||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
|
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return GCodePreviewData::Color::Dummy;
|
return Color{};
|
||||||
}
|
}
|
||||||
|
|
||||||
return GCodePreviewData::Color::Dummy;
|
return Color{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5942,7 +5942,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||||||
if (! values.empty()) {
|
if (! values.empty()) {
|
||||||
m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size());
|
m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size());
|
||||||
for (const float value : values)
|
for (const float value : values)
|
||||||
roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba, vertex_buffer_prealloc_size));
|
roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba.data(), vertex_buffer_prealloc_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6025,7 +6025,7 @@ inline void travel_paths_internal(
|
|||||||
by_type.reserve(values.size());
|
by_type.reserve(values.size());
|
||||||
// creates a new volume for each feedrate
|
// creates a new volume for each feedrate
|
||||||
for (TYPE type : values)
|
for (TYPE type : values)
|
||||||
by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba, VERTEX_BUFFER_RESERVE_SIZE));
|
by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba.data(), VERTEX_BUFFER_RESERVE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
// populates volumes
|
// populates volumes
|
||||||
@ -6072,19 +6072,19 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data,
|
|||||||
case GCodePreviewData::Extrusion::Feedrate:
|
case GCodePreviewData::Extrusion::Feedrate:
|
||||||
travel_paths_internal<float>(preview_data,
|
travel_paths_internal<float>(preview_data,
|
||||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.feedrate; },
|
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.feedrate; },
|
||||||
[&preview_data](const float feedrate) -> const GCodePreviewData::Color { return preview_data.get_feedrate_color(feedrate); },
|
[&preview_data](const float feedrate) -> const Color { return preview_data.get_feedrate_color(feedrate); },
|
||||||
m_volumes, m_initialized);
|
m_volumes, m_initialized);
|
||||||
break;
|
break;
|
||||||
case GCodePreviewData::Extrusion::Tool:
|
case GCodePreviewData::Extrusion::Tool:
|
||||||
travel_paths_internal<unsigned int>(preview_data,
|
travel_paths_internal<unsigned int>(preview_data,
|
||||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.extruder_id; },
|
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.extruder_id; },
|
||||||
[&tool_colors](const unsigned int extruder_id) -> const GCodePreviewData::Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return GCodePreviewData::Color(tool_colors.data() + extruder_id * 4); },
|
[&tool_colors](const unsigned int extruder_id) -> const Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return Color(tool_colors.data() + extruder_id * 4); },
|
||||||
m_volumes, m_initialized);
|
m_volumes, m_initialized);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
travel_paths_internal<unsigned int>(preview_data,
|
travel_paths_internal<unsigned int>(preview_data,
|
||||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.type; },
|
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.type; },
|
||||||
[&preview_data](const unsigned int type) -> const GCodePreviewData::Color& { return preview_data.travel.type_colors[type]; },
|
[&preview_data](const unsigned int type) -> const Color& { return preview_data.travel.type_colors[type]; },
|
||||||
m_volumes, m_initialized);
|
m_volumes, m_initialized);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -533,7 +533,9 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
|
|||||||
void Preview::on_checkbox_travel(wxCommandEvent& evt)
|
void Preview::on_checkbox_travel(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
m_gcode_preview_data->travel.is_visible = m_checkbox_travel->IsChecked();
|
m_gcode_preview_data->travel.is_visible = m_checkbox_travel->IsChecked();
|
||||||
refresh_print();
|
m_gcode_preview_data->ranges.feedrate.set_mode(GCodePreviewData::FeedrateKind::TRAVEL, m_gcode_preview_data->travel.is_visible);
|
||||||
|
// Rather than refresh, reload print so that speed color ranges get recomputed (affected by travel visibility)
|
||||||
|
reload_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preview::on_checkbox_retractions(wxCommandEvent& evt)
|
void Preview::on_checkbox_retractions(wxCommandEvent& evt)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user