From 329ad97a842ce6f1436fd202c854c6b41f8d6422 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Wed, 4 Dec 2019 09:31:21 +0100 Subject: [PATCH 01/85] Add int() and % (modulo) --- src/libslic3r/PlaceholderParser.cpp | 35 +++++++++++++++++++++++++++++ t/custom_gcode.t | 3 +++ 2 files changed, 38 insertions(+) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 0cfd97415..c92be2845 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -332,6 +332,21 @@ namespace client return expr(); } + expr unary_integer(const Iterator start_pos) const + { + switch (this->type) { + case TYPE_INT : + return expr(this->i(), start_pos, this->it_range.end()); + case TYPE_DOUBLE: + return expr((int)(this->d()), start_pos, this->it_range.end()); + default: + this->throw_exception("Cannot convert to integer."); + } + assert(false); + // Suppress compiler warnings. + return expr(); + } + expr unary_not(const Iterator start_pos) const { switch (this->type) { @@ -415,6 +430,22 @@ namespace client return *this; } + expr &operator%=(const expr &rhs) + { + this->throw_if_not_numeric("Cannot divide a non-numeric type."); + rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); + if ((this->type == TYPE_INT) ? (rhs.i() == 0) : (rhs.d() == 0.)) + rhs.throw_exception("Division by zero"); + if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { + double d = std::fmod(this->as_d(), rhs.as_d()); + this->data.d = d; + this->type = TYPE_DOUBLE; + } else + this->data.i %= rhs.i(); + this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + return *this; + } + static void to_string2(expr &self, std::string &out) { out = self.to_string(); @@ -1087,6 +1118,7 @@ namespace client unary_expression(_r1) [_val = _1] >> *( (lit('*') > unary_expression(_r1) ) [_val *= _1] | (lit('/') > unary_expression(_r1) ) [_val /= _1] + | (lit('%') > unary_expression(_r1) ) [_val %= _1] ); multiplicative_expression.name("multiplicative_expression"); @@ -1107,6 +1139,8 @@ namespace client { out = value.unary_minus(out.it_range.begin()); } static void not_(expr &value, expr &out) { out = value.unary_not(out.it_range.begin()); } + static void to_int(expr &value, expr &out) + { out = value.unary_integer(out.it_range.begin()); } }; unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( scalar_variable_reference(_r1) [ _val = _1 ] @@ -1118,6 +1152,7 @@ namespace client [ px::bind(&expr::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') [ px::bind(&expr::max, _val, _2) ] + | (kw["int"] > '(' > unary_expression(_r1) ) [ px::bind(&FactorActions::to_int, _1, _val) ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] diff --git a/t/custom_gcode.t b/t/custom_gcode.t index 4c1c1b108..5ffd9b7f4 100644 --- a/t/custom_gcode.t +++ b/t/custom_gcode.t @@ -67,6 +67,8 @@ use Slic3r::Test; is $parser->process('{2*3/6}'), '1', 'math: 2*3/6'; is $parser->process('{2*3/12}'), '0', 'math: 2*3/12'; ok abs($parser->process('{2.*3/12}') - 0.5) < 1e-7, 'math: 2.*3/12'; + is $parser->process('{10%2.5}') '0', 'math: 10 % 2.5'; + is $parser->process('{11/2.5-1}') '1', 'math: 11 % 2.5'; is $parser->process('{2*(3-12)}'), '-18', 'math: 2*(3-12)'; is $parser->process('{2*foo*(3-12)}'), '0', 'math: 2*foo*(3-12)'; is $parser->process('{2*bar*(3-12)}'), '-36', 'math: 2*bar*(3-12)'; @@ -75,6 +77,7 @@ use Slic3r::Test; is $parser->process('{max(12, 14)}'), '14', 'math: max(12, 14)'; is $parser->process('{min(13.4, -1238.1)}'), '-1238.1', 'math: min(13.4, -1238.1)'; is $parser->process('{max(13.4, -1238.1)}'), '13.4', 'math: max(13.4, -1238.1)'; + is $parser->process('{int(13.4)}'), '13', 'math: int(13.4)'; # Test the boolean expression parser. is $parser->evaluate_boolean_expression('12 == 12'), 1, 'boolean expression parser: 12 == 12'; From dea83da5b7072bab649b31a58d282c504f27623e Mon Sep 17 00:00:00 2001 From: foxox Date: Sat, 7 Dec 2019 19:31:28 -0500 Subject: [PATCH 02/85] Speed legend scales depending on travel visibility. --- src/libslic3r/GCode/Analyzer.cpp | 8 +- src/libslic3r/GCode/PreviewData.cpp | 138 +++++++++---------- src/libslic3r/GCode/PreviewData.hpp | 198 ++++++++++++++++++++++++---- src/slic3r/GUI/GLCanvas3D.cpp | 26 ++-- src/slic3r/GUI/GUI_Preview.cpp | 4 +- 5 files changed, 254 insertions(+), 120 deletions(-) diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index f73f4b4ba..a9be609be 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -993,7 +993,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ float volumetric_rate = FLT_MAX; GCodePreviewData::Range height_range; GCodePreviewData::Range width_range; - GCodePreviewData::Range feedrate_range; + GCodePreviewData::MultiRange feedrate_range; GCodePreviewData::Range volumetric_rate_range; GCodePreviewData::Range fan_speed_range; @@ -1028,7 +1028,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm; height_range.update_from(move.data.height); 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); fan_speed_range.update_from(move.data.fan_speed); } @@ -1081,7 +1081,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s GCodePreviewData::Range height_range; GCodePreviewData::Range width_range; - GCodePreviewData::Range feedrate_range; + GCodePreviewData::MultiRange feedrate_range; // to avoid to call the callback too often unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1); @@ -1121,7 +1121,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s extruder_id = move.data.extruder_id; height_range.update_from(move.data.height); 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 diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index e7475089a..64057ec8d 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -11,9 +11,7 @@ namespace Slic3r { -const GCodePreviewData::Color GCodePreviewData::Color::Dummy(0.0f, 0.0f, 0.0f, 0.0f); - -std::vector GCodePreviewData::Color::as_bytes() const +std::vector Color::as_bytes() const { std::vector ret; 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() { reset(); @@ -59,54 +43,52 @@ GCodePreviewData::Range::Range() void GCodePreviewData::Range::reset() { - min = FLT_MAX; - max = -FLT_MAX; + min_val = FLT_MAX; + max_val = -FLT_MAX; } bool GCodePreviewData::Range::empty() const { - return min == max; + return min_val >= max_val; } void GCodePreviewData::Range::update_from(float value) { - min = std::min(min, value); - max = std::max(max, value); + min_val = std::min(min_val, 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); - max = std::max(max, other.max); + min_val = std::min(min_val, other.min()); + 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; - max = other.max; + return (max() - min()) / static_cast(range_rainbow_colors.size() - 1); } -float GCodePreviewData::Range::step_size() const -{ - return (max - min) / (float)(Colors_Count - 1); -} - -GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const +Color GCodePreviewData::RangeBase::get_color_at(float value) const { 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; - unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1); + // Compute the two colors just below (low) and above (high) the input value + const std::size_t color_low_idx = clamp(std::size_t{0}, color_max_idx, static_cast(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]; - Color color_high = colors[high]; + // Compute how far the value is between the low and high colors so that they can be interpolated + const float local_t = std::min(global_t - static_cast(color_low_idx), 1.0f); // upper limit of 1.0f - float local_t = global_t - (float)low; - - // interpolate in RGB space + // Interpolate between the low and high colors in RGB space to find exactly which color the input value should get Color ret; for (unsigned int i = 0; i < 4; ++i) { @@ -115,13 +97,23 @@ GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const 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) , 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(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_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.75f, 0.0f, 1.0f), // Extrude @@ -206,7 +198,7 @@ size_t GCodePreviewData::Travel::memory_used() const 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) : position(position) @@ -238,17 +230,15 @@ GCodePreviewData::GCodePreviewData() 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(); travel.set_default(); retraction.set_default(); unretraction.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() @@ -268,32 +258,32 @@ bool GCodePreviewData::empty() const 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]; } -GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const +Color GCodePreviewData::get_height_color(float height) const { 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); } -GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const +Color GCodePreviewData::get_feedrate_color(float feedrate) const { 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); } -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); } @@ -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& colors) { - unsigned int size = (unsigned int)colors.size(); + unsigned int size = (unsigned int)range_rainbow_colors.size(); if (size % 2 != 0) return; @@ -384,16 +374,16 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: { 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(); - for (int i = Range::Colors_Count - 1; i >= 0; --i) + for (int i = static_cast(range_rainbow_colors.size()) - 1; i >= 0; --i) { char buf[1024]; - sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step)); - list.emplace_back(buf, range.colors[i]); + sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step)); + 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); for (unsigned int i = 0; i < tools_colors_count; ++i) { - GCodePreviewData::Color color; - ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float)); + Color color; + ::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); } @@ -460,7 +450,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: if (color_print_cnt == 1) // means "Default print 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); break; @@ -472,7 +462,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: for (int i = 0 ; i < color_print_cnt; ++i) { 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); } @@ -496,23 +486,23 @@ size_t GCodePreviewData::memory_used() const sizeof(shell) + sizeof(ranges); } -const std::vector& GCodePreviewData::ColorPrintColors() +const std::vector& ColorPrintColors() { static std::vector color_print = {"#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6"}; 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[2] + c2.rgba[2]), 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[2]), clamp(0.0f, 1.0f, f * color.rgba[3])); diff --git a/src/libslic3r/GCode/PreviewData.hpp b/src/libslic3r/GCode/PreviewData.hpp index 725c0258d..a023203f1 100644 --- a/src/libslic3r/GCode/PreviewData.hpp +++ b/src/libslic3r/GCode/PreviewData.hpp @@ -5,43 +5,188 @@ #include "../ExtrusionEntity.hpp" #include "../Point.hpp" +#include +#include +#include +#include +#include +#include +#include + namespace Slic3r { +// Represents an RGBA color +struct Color +{ + std::array 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 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 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 { 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); } - 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; } - - std::vector as_bytes() const; - - static const Color Dummy; + virtual void reset() = 0; + virtual bool empty() const = 0; + virtual float min() const = 0; + virtual float max() const = 0; + + // 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 range into a smooth rainbow of 10 colors. - struct Range + + // Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors. + class Range : public RangeBase { - static const unsigned int Colors_Count = 10; - static const Color Default_Colors[Colors_Count]; - - Color colors[Colors_Count]; - float min; - float max; - + public: Range(); - void reset(); - bool empty() const; + // RangeBase Overrides + 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(const Range& other); - void set_from(const Range& other); - float step_size() const; + void update_from(const RangeBase& other); - 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 + 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(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(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(EnumRangeType::num_values)> bounds; + std::bitset(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 @@ -51,7 +196,7 @@ public: // Color mapping by extrusion width. Range width; // Color mapping by feedrate. - Range feedrate; + MultiRange feedrate; // Color mapping by fan speed. Range fan_speed; // Color mapping by volumetric extrusion rate. @@ -245,9 +390,6 @@ public: static const std::vector& ColorPrintColors(); }; -GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2); -GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color); - } // namespace Slic3r #endif /* slic3r_GCode_PreviewData_hpp_ */ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index dcf45e91d..24cb6a192 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2417,7 +2417,7 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio 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); std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); }); @@ -5841,7 +5841,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat return 0.0f; } - static GCodePreviewData::Color path_color(const GCodePreviewData& data, const std::vector& tool_colors, float value) + static Color path_color(const GCodePreviewData& data, const std::vector& tool_colors, float value) { switch (data.extrusion.view_type) { @@ -5859,8 +5859,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat return data.get_volumetric_rate_color(value); case GCodePreviewData::Extrusion::Tool: { - GCodePreviewData::Color color; - ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float)); + Color color; + ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float)); return color; } case GCodePreviewData::Extrusion::ColorPrint: @@ -5868,16 +5868,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat int color_cnt = (int)tool_colors.size() / 4; int val = value > color_cnt ? color_cnt - 1 : value; - GCodePreviewData::Color color; - ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float)); + Color color; + ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float)); return color; } default: - return GCodePreviewData::Color::Dummy; + return Color{}; } - return GCodePreviewData::Color::Dummy; + return Color{}; } }; @@ -5920,7 +5920,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat if (! values.empty()) { m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size()); 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)); } } } @@ -6003,7 +6003,7 @@ inline void travel_paths_internal( by_type.reserve(values.size()); // creates a new volume for each feedrate 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 @@ -6050,19 +6050,19 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, case GCodePreviewData::Extrusion::Feedrate: travel_paths_internal(preview_data, [](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); break; case GCodePreviewData::Extrusion::Tool: travel_paths_internal(preview_data, [](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); break; default: travel_paths_internal(preview_data, [](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); break; } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index edb244b34..1e4465925 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -538,7 +538,9 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt) void Preview::on_checkbox_travel(wxCommandEvent& evt) { 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) From 6a8c34dad9adfb29bf6198df289cd07f8d85065b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 2 Jan 2020 13:41:49 +0100 Subject: [PATCH 03/85] Checking of icons for dark mode is removed to BitmapCache --- src/slic3r/GUI/BitmapCache.cpp | 29 +++++++++++++++++++++++------ src/slic3r/GUI/BitmapCache.hpp | 2 +- src/slic3r/GUI/wxExtensions.cpp | 14 +++++++------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index f7cefe72b..ae4c21ccb 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -1,6 +1,7 @@ #include "BitmapCache.hpp" #include "libslic3r/Utils.hpp" +#include #if ! defined(WIN32) && ! defined(__APPLE__) #define BROKEN_ALPHA @@ -15,7 +16,7 @@ #include "nanosvg/nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION #include "nanosvg/nanosvgrast.h" -#include "GUI_App.hpp" +//#include "GUI_App.hpp" namespace Slic3r { namespace GUI { @@ -226,24 +227,40 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, } wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height, - float scale /* = 1.0f */, const bool grayscale/* = false*/) + float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/) { - std::string bitmap_key = bitmap_name + ( target_height !=0 ? + /* For the Dark mode of any platform, we should draw icons in respect to OS background + * Note: All standard(regular) icons are collected in "icons" folder, + * SVG-icons, which have "Dark mode" variant, are collected in "icons/white" folder + */ + std::string folder; + if (dark_mode) + { +#ifdef __WXMSW__ + folder = "white\\"; +#else + folder = "white/"; +#endif + if (!boost::filesystem::exists(Slic3r::var(folder + bitmap_name + ".svg"))) + folder.clear(); + } + + std::string bitmap_key = folder + bitmap_name + ( target_height !=0 ? "-h" + std::to_string(target_height) : "-w" + std::to_string(target_width)) + (scale != 1.0f ? "-s" + std::to_string(scale) : "") + (grayscale ? "-gs" : ""); - target_height != 0 ? target_height *= scale : target_width *= scale; - auto it = m_map.find(bitmap_key); if (it != m_map.end()) return it->second; - NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f); + NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(folder + bitmap_name + ".svg").c_str(), "px", 96.0f); if (image == nullptr) return nullptr; + target_height != 0 ? target_height *= scale : target_width *= scale; + float svg_scale = target_height != 0 ? (float)target_height / image->height : target_width != 0 ? (float)target_width / image->width : 1; diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index ce77057c8..041e7d892 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -34,7 +34,7 @@ public: // Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero. wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false); // Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width. - wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false); + wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false); static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 7b36207f5..78950e029 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -13,9 +13,8 @@ #include #include -#include +//#include #include -#include #include "BitmapCache.hpp" #include "GUI.hpp" @@ -427,6 +426,7 @@ static float get_svg_scale_factor(wxWindow *win) } // in the Dark mode of any platform, we should draw icons in respect to OS background +/* static std::string icon_name_respected_to_mode(const std::string& bmp_name_in) { #ifdef __WXMSW__ @@ -447,7 +447,7 @@ static std::string icon_name_respected_to_mode(const std::string& bmp_name_in) } return bmp_name; } - +*/ // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/, const bool grayscale/* = false*/) @@ -474,13 +474,13 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, scale_base = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f); -// std::string bmp_name = bmp_name_in; -// boost::replace_last(bmp_name, ".png", ""); + std::string bmp_name = bmp_name_in; + boost::replace_last(bmp_name, ".png", ""); - std::string bmp_name = icon_name_respected_to_mode(bmp_name_in); +// std::string bmp_name = icon_name_respected_to_mode(bmp_name_in); // Try loading an SVG first, then PNG if SVG is not found: - wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale); + wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale, Slic3r::GUI::wxGetApp().dark_mode()); if (bmp == nullptr) { bmp = cache.load_png(bmp_name, width, height, grayscale); } From 4f1f507d5a181c57e272d5980c7ff6cd45575c34 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 6 Jan 2020 12:40:58 +0100 Subject: [PATCH 04/85] Fix of #3371 --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5b27c8870..d2428cf96 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1137,6 +1137,12 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c // calculate scaling const float scale_gl = canvas.get_canvas_size().get_scale_factor(); +#if ENABLE_RETINA_GL + // For non-visible or non-created window getBackingScaleFactor function return 0.0 value. + // And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle + if (scale_gl <= 0.0f) + return false; +#endif const float scale = scale_gl * wxGetApp().em_unit()*0.1; // get scale from em_unit() value, because of get_scale_factor() return 1 const int scaled_square = std::floor((float)Px_Square * scale); const int scaled_title_offset = Px_Title_Offset * scale; From bea82a4501d1d2542139affe8455faefe7c6eca9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 7 Jan 2020 08:46:11 +0100 Subject: [PATCH 05/85] Fixed density calculation is wrong for resin cost calculation (#3460) --- src/slic3r/GUI/Tab.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index adc923b64..353e822e3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3444,15 +3444,15 @@ void TabSLAMaterial::build() DynamicPrintConfig new_conf = *m_config; if (opt_key == "bottle_volume") { - double new_bottle_weight = boost::any_cast(value)/(new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_weight = boost::any_cast(value)*(new_conf.option("material_density")->getFloat() / 1000); new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); } if (opt_key == "bottle_weight") { - double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_volume = boost::any_cast(value)/(new_conf.option("material_density")->getFloat() * 1000); new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { - double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() * boost::any_cast(value) * 1000; + double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() / boost::any_cast(value) * 1000; new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } From 5b2e2fe7b3956fc13b8ce8e0e35db4d3278c50a8 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 7 Jan 2020 12:40:03 +0100 Subject: [PATCH 06/85] Fixed artifacts on toolbar and gizmobar icons showing up when changing screen or toolbar scale factors --- src/libslic3r/Technologies.hpp | 4 ++ src/slic3r/GUI/GLTexture.cpp | 51 ++++++++++++++++++++++- src/slic3r/GUI/GLToolbar.cpp | 33 ++++++++++++++- src/slic3r/GUI/GLToolbar.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 38 ++++++++++++++++- 5 files changed, 123 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 64c5ce953..bc3ec6c44 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,4 +68,8 @@ // Enable using Y axis of 3Dconnexion devices as zoom #define ENABLE_3DCONNEXION_Y_AS_ZOOM (1 && ENABLE_2_2_0_BETA1) +// Enable a modified version of the toolbar textures where all the icons are separated by 1 pixel +#define ENABLE_MODIFIED_TOOLBAR_TEXTURES (1 && ENABLE_2_2_0_BETA1) + + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 62129cfc0..2834c9603 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -168,12 +168,26 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorwidth, image->height); +#if ENABLE_MODIFIED_TOOLBAR_TEXTURES + // offset by 1 to leave the first pixel empty (both in x and y) + nsvgRasterize(rast, image, 1, 1, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_stride); +#else nsvgRasterize(rast, image, 0, 0, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_stride); +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES // makes white only copy of the sprite ::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes); @@ -231,7 +250,11 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& state : states) { @@ -250,6 +273,23 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorGLTexture::Quad_UVs + { + assert((tex_width != 0) && (tex_height != 0)); + GLTexture::Quad_UVs ret; + // tiles in the texture are spaced by 1 pixel + float icon_size_px = (float)(tex_width - 1) / (float)Num_States; + float inv_tex_width = 1.0f / (float)tex_width; + float inv_tex_height = 1.0f / (float)tex_height; + // tiles in the texture are spaced by 1 pixel + float u_offset = 1.0f * inv_tex_width; + float v_offset = 1.0f * inv_tex_height; + float du = icon_size_px * inv_tex_width; + float dv = icon_size_px * inv_tex_height; + float left = u_offset + (float)m_state * du; + float right = left + du - u_offset; + float top = v_offset + (float)m_data.sprite_id * dv; + float bottom = top + dv - v_offset; + ret.left_top = { left, top }; + ret.left_bottom = { left, bottom }; + ret.right_bottom = { right, bottom }; + ret.right_top = { right, top }; + return ret; + }; + + GLTexture::render_sub_texture(tex_id, left, right, bottom, top, uvs(tex_width, tex_height, icon_size)); +#else GLTexture::render_sub_texture(tex_id, left, right, bottom, top, get_uvs(tex_width, tex_height, icon_size)); +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES if (is_pressed()) { @@ -97,6 +125,7 @@ void GLToolbarItem::render(unsigned int tex_id, float left, float right, float b } } +#if !ENABLE_MODIFIED_TOOLBAR_TEXTURES GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const { GLTexture::Quad_UVs uvs; @@ -110,14 +139,14 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int float right = left + scaled_icon_width; float top = (float)m_data.sprite_id * scaled_icon_height; float bottom = top + scaled_icon_height; - uvs.left_top = { left, top }; uvs.left_bottom = { left, bottom }; uvs.right_bottom = { right, bottom }; uvs.right_top = { right, top }; - + return uvs; } +#endif // !ENABLE_MODIFIED_TOOLBAR_TEXTURES BackgroundTexture::Metadata::Metadata() : filename("") diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index eb73dcdfd..bbc773de2 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -143,7 +143,9 @@ public: void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const; private: +#if !ENABLE_MODIFIED_TOOLBAR_TEXTURES GLTexture::Quad_UVs get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const; +#endif // !ENABLE_MODIFIED_TOOLBAR_TEXTURES void set_visible(bool visible) { m_data.visible = visible; } friend class GLToolbar; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index b5e2c99c5..959d7d3ed 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -838,8 +838,14 @@ void GLGizmosManager::render_background(float left, float top, float right, floa void GLGizmosManager::do_render_overlay() const { +#if ENABLE_MODIFIED_TOOLBAR_TEXTURES + std::vector selectable_idxs = get_selectable_idxs(); + if (selectable_idxs.empty()) + return; +#else if (m_gizmos.empty()) return; +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES float cnv_w = (float)m_parent.get_canvas_size().get_width(); float cnv_h = (float)m_parent.get_canvas_size().get_height(); @@ -870,13 +876,34 @@ void GLGizmosManager::do_render_overlay() const unsigned int icons_texture_id = m_icons_texture.get_id(); int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f; - float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f; +#if ENABLE_MODIFIED_TOOLBAR_TEXTURES + if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)) + return; + +#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE + float du = (float)(tex_width - 1) / (4.0f * (float)tex_width); // 4 is the number of possible states if the icons +#else + float du = (float)(tex_width - 1) / (3.0f * (float)tex_width); // 3 is the number of possible states if the icons +#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE + float dv = (float)(tex_height - 1) / (float)(selectable_idxs.size() * tex_height); + + // tiles in the texture are spaced by 1 pixel + float u_offset = 1.0f / (float)tex_width; + float v_offset = 1.0f / (float)tex_height; +#else if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; + float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f; + float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f; +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES + +#if ENABLE_MODIFIED_TOOLBAR_TEXTURES + for (size_t idx : selectable_idxs) +#else for (size_t idx : get_selectable_idxs()) +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES { GLGizmoBase* gizmo = m_gizmos[idx].get(); @@ -887,6 +914,12 @@ void GLGizmosManager::do_render_overlay() const int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0); #endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE +#if ENABLE_MODIFIED_TOOLBAR_TEXTURES + float v_top = v_offset + sprite_id * dv; + float u_left = u_offset + icon_idx * du; + float v_bottom = v_top + dv - v_offset; + float u_right = u_left + du - u_offset; +#else float u_icon_size = icons_size * inv_tex_width; float v_icon_size = icons_size * inv_tex_height; @@ -894,6 +927,7 @@ void GLGizmosManager::do_render_overlay() const float u_left = icon_idx * u_icon_size; float v_bottom = v_top + v_icon_size; float u_right = u_left + u_icon_size; +#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); if (idx == m_current) { From 8559360cf8314c0630b1a5774c317db6adb3dbe6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 7 Jan 2020 13:17:39 +0100 Subject: [PATCH 07/85] #3385 - Further extended min/max sensitivity for 3Dconnexion devices --- src/slic3r/GUI/Mouse3DController.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 707a1d143..38432d0d3 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -321,16 +321,16 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign ImGui::PopStyleColor(); float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; - if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.2f, 5.0f, "%.1f")) + if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.1f, 10.0f, "%.1f")) m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; - if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.2f, 5.0f, "%.1f")) + if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.1f, 10.0f, "%.1f")) m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); #if ENABLE_3DCONNEXION_Y_AS_ZOOM float zoom_scale = m_state.get_zoom_scale() / State::DefaultZoomScale; - if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.2f, 5.0f, "%.1f")) + if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.1f, 10.0f, "%.1f")) m_state.set_zoom_scale(State::DefaultZoomScale * zoom_scale); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM @@ -662,12 +662,12 @@ bool Mouse3DController::connect_device() wxGetApp().app_config->get_mouse_device_zoom_speed(m_device_str, zoom_speed); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // clamp to valid values - m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.2, 5.0)); + m_state.set_translation_scale(State::DefaultTranslationScale* std::clamp(translation_speed, 0.1, 10.0)); m_state.set_translation_deadzone(std::clamp(translation_deadzone, 0.0, State::MaxTranslationDeadzone)); - m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.2f, 5.0f)); + m_state.set_rotation_scale(State::DefaultRotationScale* std::clamp(rotation_speed, 0.1f, 10.0f)); m_state.set_rotation_deadzone(std::clamp(rotation_deadzone, 0.0f, State::MaxRotationDeadzone)); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.2, 5.0)); + m_state.set_zoom_scale(State::DefaultZoomScale* std::clamp(zoom_speed, 0.1, 10.0)); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM } #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT From 70bc392003738cf30882f40ca9a7501b24db80f8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 7 Jan 2020 14:08:21 +0100 Subject: [PATCH 08/85] Support for Vendor / Printer Model specific print bed texture and model. --- src/slic3r/GUI/3DBed.cpp | 32 ++++++++++++++++++++++++++++++++ src/slic3r/GUI/Preset.cpp | 2 ++ src/slic3r/GUI/Preset.hpp | 3 +++ 3 files changed, 37 insertions(+) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index f6f80d822..ecbca4228 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -341,6 +341,38 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) printf("Unable to create bed grid lines\n"); } +static const VendorProfile::PrinterModel* system_printer_model(const Preset &preset) +{ + const VendorProfile::PrinterModel *out = nullptr; + if (preset.vendor != nullptr) { + auto *printer_model = preset.config.opt("printer_model"); + if (printer_model != nullptr && ! printer_model->value.empty()) { + auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; }); + if (it != preset.vendor->models.end()) + out = &(*it); + } + } + return out; +} + +static std::string system_print_bed_model(const Preset &preset) +{ + std::string out; + const VendorProfile::PrinterModel *pm = system_printer_model(preset); + if (pm != nullptr && ! pm->bed_model.empty()) + out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model; + return out; +} + +static std::string system_print_bed_texture(const Preset &preset) +{ + std::string out; + const VendorProfile::PrinterModel *pm = system_printer_model(preset); + if (pm != nullptr && ! pm->bed_texture.empty()) + out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture; + return out; +} + Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const { EType type = Custom; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index c2439b26f..c20a5bb28 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -184,6 +184,8 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem } else { BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed variants field: `%2%`") % id % variants_field; } + model.bed_model = section.second.get("bed_model", ""); + model.bed_texture = section.second.get("bed_texture", ""); if (! model.id.empty() && ! model.variants.empty()) res.models.push_back(std::move(model)); } diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 547814559..55791eb09 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -61,6 +61,9 @@ public: PrinterTechnology technology; std::string family; std::vector variants; + // Vendor & Printer Model specific print bed model & texture. + std::string bed_model; + std::string bed_texture; PrinterVariant* variant(const std::string &name) { for (auto &v : this->variants) From 81187e7e0e1586117ca3b1d8b2f708f2b1e14400 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 7 Jan 2020 14:35:43 +0100 Subject: [PATCH 09/85] Some refactoring and const correctness fixes. --- src/libslic3r/Config.hpp | 4 ++-- src/libslic3r/GCode/ToolOrdering.cpp | 16 +++++++++++++++- src/libslic3r/GCode/ToolOrdering.hpp | 22 ++++------------------ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 87a79d93f..e7ecc2977 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -289,13 +289,13 @@ public: throw std::runtime_error("ConfigOptionVector::set_at(): Assigning an incompatible type"); } - T& get_at(size_t i) + const T& get_at(size_t i) const { assert(! this->values.empty()); return (i < this->values.size()) ? this->values[i] : this->values.front(); } - const T& get_at(size_t i) const { return const_cast*>(this)->get_at(i); } + T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index b7d1d57df..bcb65554d 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -394,7 +394,21 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) } } - +const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const +{ + auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); + assert(it_layer_tools != m_layer_tools.end()); + coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); + for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++ it_layer_tools) { + coordf_t d = std::abs(it_layer_tools->print_z - print_z); + if (d >= dist_min) + break; + dist_min = d; + } + -- it_layer_tools; + assert(dist_min < EPSILON); + return *it_layer_tools; +} // This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual) void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 0d4b83ecb..c37c90823 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -5,6 +5,8 @@ #include "../libslic3r.h" +#include + namespace Slic3r { class Print; @@ -123,25 +125,9 @@ public: // For a multi-material print, the printing extruders are ordered in the order they shall be primed. const std::vector& all_extruders() const { return m_all_printing_extruders; } - template static auto tools_for_layer(Self& self, coordf_t print_z) -> decltype (*self.m_layer_tools.begin()) - { - auto it_layer_tools = std::lower_bound(self.m_layer_tools.begin(), self.m_layer_tools.end(), LayerTools(print_z - EPSILON)); - assert(it_layer_tools != self.m_layer_tools.end()); - coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); - for (++ it_layer_tools; it_layer_tools != self.m_layer_tools.end(); ++it_layer_tools) { - coordf_t d = std::abs(it_layer_tools->print_z - print_z); - if (d >= dist_min) - break; - dist_min = d; - } - -- it_layer_tools; - assert(dist_min < EPSILON); - return *it_layer_tools; - } - // Find LayerTools with the closest print_z. - LayerTools& tools_for_layer(coordf_t print_z) { return tools_for_layer(*this, print_z); } - const LayerTools& tools_for_layer(coordf_t print_z) const { return tools_for_layer(*this, print_z); } + const LayerTools& tools_for_layer(coordf_t print_z) const; + LayerTools& tools_for_layer(coordf_t print_z) { return const_cast(std::as_const(*this).tools_for_layer(print_z)); } const LayerTools& front() const { return m_layer_tools.front(); } const LayerTools& back() const { return m_layer_tools.back(); } From ca950d1a007cd83f075c9fbdb5b9c115a0b49b99 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 7 Jan 2020 15:22:18 +0100 Subject: [PATCH 10/85] Added check for a preset visibility in a first_compatible_idx() function (related to #3470) --- src/slic3r/GUI/Preset.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 55791eb09..19d07d007 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -383,7 +383,8 @@ public: size_t n = this->m_presets.size(); size_t i_compatible = n; for (; i < n; ++ i) - if (m_presets[i].is_compatible) { + // Since we use the filament selection from Wizard, it's needed to control the preset visibility too + if (m_presets[i].is_compatible && m_presets[i].is_visible) { if (prefered_condition(m_presets[i].name)) return i; if (i_compatible == n) From e531b0319f8425f56a9360d71e25ad25b803b369 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 7 Jan 2020 16:17:20 +0100 Subject: [PATCH 11/85] Code cleaning and refactoring for https://github.com/prusa3d/PrusaSlicer/commit/6a8c34dad9adfb29bf6198df289cd07f8d85065b --- src/slic3r/GUI/BitmapCache.cpp | 33 +++++++++++++++++++++++---------- src/slic3r/GUI/wxExtensions.cpp | 24 ------------------------ 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index ae4c21ccb..7322a88d1 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -229,6 +229,12 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height, float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/) { + std::string bitmap_key = bitmap_name + ( target_height !=0 ? + "-h" + std::to_string(target_height) : + "-w" + std::to_string(target_width)) + + (scale != 1.0f ? "-s" + std::to_string(scale) : "") + + (grayscale ? "-gs" : ""); + /* For the Dark mode of any platform, we should draw icons in respect to OS background * Note: All standard(regular) icons are collected in "icons" folder, * SVG-icons, which have "Dark mode" variant, are collected in "icons/white" folder @@ -241,19 +247,26 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_ #else folder = "white/"; #endif + auto it = m_map.find(folder + bitmap_key); + if (it != m_map.end()) + return it->second; + else { + it = m_map.find(bitmap_key); + if (it != m_map.end()) + return it->second; + } + if (!boost::filesystem::exists(Slic3r::var(folder + bitmap_name + ".svg"))) folder.clear(); + else + bitmap_key = folder + bitmap_key; + } + else + { + auto it = m_map.find(bitmap_key); + if (it != m_map.end()) + return it->second; } - - std::string bitmap_key = folder + bitmap_name + ( target_height !=0 ? - "-h" + std::to_string(target_height) : - "-w" + std::to_string(target_width)) - + (scale != 1.0f ? "-s" + std::to_string(scale) : "") - + (grayscale ? "-gs" : ""); - - auto it = m_map.find(bitmap_key); - if (it != m_map.end()) - return it->second; NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(folder + bitmap_name + ".svg").c_str(), "px", 96.0f); if (image == nullptr) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 78950e029..ae27f6d03 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -13,7 +13,6 @@ #include #include -//#include #include #include "BitmapCache.hpp" @@ -425,29 +424,6 @@ static float get_svg_scale_factor(wxWindow *win) #endif } -// in the Dark mode of any platform, we should draw icons in respect to OS background -/* -static std::string icon_name_respected_to_mode(const std::string& bmp_name_in) -{ -#ifdef __WXMSW__ - const std::string folder = "white\\"; -#else - const std::string folder = "white/"; -#endif - std::string bmp_name; - if (Slic3r::GUI::wxGetApp().dark_mode()) { - bmp_name = folder + bmp_name_in; - boost::replace_last(bmp_name, ".png", ""); - if (! boost::filesystem::exists(Slic3r::var(bmp_name + ".svg"))) - bmp_name.clear(); - } - if (bmp_name.empty()) { - bmp_name = bmp_name_in; - boost::replace_last(bmp_name, ".png", ""); - } - return bmp_name; -} -*/ // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/, const bool grayscale/* = false*/) From 5a63b9a6a0e5ead36ec5f8943e211ecf2bd6f513 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 8 Jan 2020 10:04:39 +0100 Subject: [PATCH 12/85] Follow-up of 5b2e2fe7b3956fc13b8ce8e0e35db4d3278c50a8 -> Fixed uv mapping on gizmobar --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 959d7d3ed..abcb39c14 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -886,7 +886,7 @@ void GLGizmosManager::do_render_overlay() const #else float du = (float)(tex_width - 1) / (3.0f * (float)tex_width); // 3 is the number of possible states if the icons #endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE - float dv = (float)(tex_height - 1) / (float)(selectable_idxs.size() * tex_height); + float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height); // tiles in the texture are spaced by 1 pixel float u_offset = 1.0f / (float)tex_width; From abd432e7a8f91bba876a29c857844c93dab4b762 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 8 Jan 2020 11:11:38 +0100 Subject: [PATCH 13/85] Configurable paths export (fullpath or not) to 3mf and amf --- src/PrusaSlicer.cpp | 8 ++++ src/libslic3r/Format/3mf.cpp | 50 +++++++++++++++++++++++++ src/libslic3r/Format/3mf.hpp | 8 ++++ src/libslic3r/Format/AMF.cpp | 9 +++++ src/libslic3r/Format/AMF.hpp | 4 ++ src/libslic3r/Technologies.hpp | 3 ++ src/slic3r/GUI/AppConfig.cpp | 5 +++ src/slic3r/GUI/ConfigWizard.cpp | 28 ++++++++++++++ src/slic3r/GUI/ConfigWizard_private.hpp | 16 ++++++++ src/slic3r/GUI/Plater.cpp | 16 ++++++++ src/slic3r/GUI/Preferences.cpp | 10 +++++ src/slic3r/Utils/FixModelByWin10.cpp | 7 ++++ tests/libslic3r/test_3mf.cpp | 4 ++ 13 files changed, 168 insertions(+) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index d755f0b2e..28aadc045 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -641,10 +641,18 @@ bool CLI::export_models(IO::ExportFormat format) const std::string path = this->output_filepath(model, format); bool success = false; switch (format) { +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr, false); break; +#else case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr); break; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break; case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr, false); break; +#else case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF default: assert(false); break; } if (success) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 44e12db86..cca90b463 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1876,12 +1876,24 @@ namespace Slic3r { typedef std::vector BuildItemsList; typedef std::map IdToObjectDataMap; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + bool m_fullpath_sources{ true }; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + public: +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +#if ENABLE_THUMBNAIL_GENERATOR + bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr); +#else + bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources); +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr); #else bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF private: #if ENABLE_THUMBNAIL_GENERATOR @@ -1906,6 +1918,22 @@ namespace Slic3r { bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model); }; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +#if ENABLE_THUMBNAIL_GENERATOR + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data) + { + clear_errors(); + m_fullpath_sources = fullpath_sources; + return _save_model_to_file(filename, model, config, thumbnail_data); + } +#else + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources) + { + clear_errors(); + return _save_model_to_file(filename, model, config); + } +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) { @@ -1919,6 +1947,7 @@ namespace Slic3r { return _save_model_to_file(filename, model, config); } #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF #if ENABLE_THUMBNAIL_GENERATOR bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) @@ -2557,7 +2586,12 @@ namespace Slic3r { // stores volume's source data if (!volume->source.input_file.empty()) { +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + std::string input_file = xml_escape(m_fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string()); + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << input_file << "\"/>\n"; +#else stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->source.input_file) << "\"/>\n"; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OBJECT_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.object_idx << "\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_VOLUME_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.volume_idx << "\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_X_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(0) << "\"/>\n"; @@ -2646,21 +2680,37 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c return res; } +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +#if ENABLE_THUMBNAIL_GENERATOR +bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data) +#else +bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources) +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) #else bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config) #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF { if ((path == nullptr) || (model == nullptr)) return false; _3MF_Exporter exporter; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +#if ENABLE_THUMBNAIL_GENERATOR + bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data); +#else + bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources); +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR bool res = exporter.save_model_to_file(path, *model, config, thumbnail_data); #else bool res = exporter.save_model_to_file(path, *model, config); #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF if (!res) exporter.log_errors(); diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index 2e85b7f59..c28716fff 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -31,11 +31,19 @@ namespace Slic3r { // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +#if ENABLE_THUMBNAIL_GENERATOR + extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr); +#else + extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources); +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr); #else extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config); #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF }; // namespace Slic3r diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 5b65d8fa2..947c04458 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -1019,7 +1019,11 @@ bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool c return false; } +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources) +#else bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF { if ((path == nullptr) || (model == nullptr)) return false; @@ -1177,7 +1181,12 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << "\n"; if (!volume->source.input_file.empty()) { +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + std::string input_file = xml_escape(fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string()); + stream << " " << input_file << "\n"; +#else stream << " " << xml_escape(volume->source.input_file) << "\n"; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF stream << " " << volume->source.object_idx << "\n"; stream << " " << volume->source.volume_idx << "\n"; stream << " " << volume->source.mesh_offset(0) << "\n"; diff --git a/src/libslic3r/Format/AMF.hpp b/src/libslic3r/Format/AMF.hpp index 1206d60d0..7404e1e90 100644 --- a/src/libslic3r/Format/AMF.hpp +++ b/src/libslic3r/Format/AMF.hpp @@ -11,7 +11,11 @@ extern bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, // Save the given model and the config data into an amf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +extern bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources); +#else extern bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF }; // namespace Slic3r diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index bc3ec6c44..23c516a34 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -71,5 +71,8 @@ // Enable a modified version of the toolbar textures where all the icons are separated by 1 pixel #define ENABLE_MODIFIED_TOOLBAR_TEXTURES (1 && ENABLE_2_2_0_BETA1) +// Enable configurable paths export (fullpath or not) to 3mf and amf +#define ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF (1 && ENABLE_2_2_0_BETA1) + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index eb0a7fca6..bcd79274f 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -61,6 +61,11 @@ void AppConfig::set_defaults() if (get("preset_update").empty()) set("preset_update", "1"); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + if (get("export_sources_full_pathnames").empty()) + set("export_sources_full_pathnames", "1"); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + // remove old 'use_legacy_opengl' parameter from this config, if present if (!get("use_legacy_opengl").empty()) erase("", "use_legacy_opengl"); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 265e7f203..75d170b03 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -765,6 +765,23 @@ PageUpdate::PageUpdate(ConfigWizard *parent) box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); }); } +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +PageReloadFromDisk::PageReloadFromDisk(ConfigWizard* parent) + : ConfigWizardPage(parent, _(L("Reload from disk")), _(L("Reload from disk"))) + , full_pathnames(true) +{ + auto* box_pathnames = new wxCheckBox(this, wxID_ANY, _(L("Export full pathnames of models and parts sources into 3mf and amf files"))); + box_pathnames->SetValue(wxGetApp().app_config->get("export_sources_full_pathnames") == "1"); + append(box_pathnames); + append_text(_(L( + "If enabled, allows the Reload from disk command to automatically find and load the files when invoked.\n" + "If not enabled, the Reload from disk command will ask to select each file using an open file dialog." + ))); + + box_pathnames->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { this->full_pathnames = event.IsChecked(); }); +} +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + PageMode::PageMode(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("View mode")), _(L("View mode"))) { @@ -1356,6 +1373,9 @@ void ConfigWizard::priv::load_pages() btn_finish->Enable(any_fff_selected || any_sla_selected); index->add_page(page_update); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + index->add_page(page_reload_from_disk); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF index->add_page(page_mode); index->go_to(former_active); // Will restore the active item/page if possible @@ -1730,6 +1750,11 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese } app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); + +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + app_config->set("export_sources_full_pathnames", page_reload_from_disk->full_pathnames ? "1" : "0"); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + page_mode->serialize_mode(app_config); std::string preferred_model; @@ -1885,6 +1910,9 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->add_page(p->page_custom = new PageCustom(this)); p->add_page(p->page_update = new PageUpdate(this)); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + p->add_page(p->page_reload_from_disk = new PageReloadFromDisk(this)); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF p->add_page(p->page_mode = new PageMode(this)); p->add_page(p->page_firmware = new PageFirmware(this)); p->add_page(p->page_bed = new PageBedShape(this)); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index a90832a3f..3ea5321f8 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -301,6 +301,17 @@ struct PageUpdate: ConfigWizardPage PageUpdate(ConfigWizard *parent); }; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +struct PageReloadFromDisk : ConfigWizardPage +{ + bool full_pathnames; + + PageReloadFromDisk(ConfigWizard* parent); +}; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + struct PageMode: ConfigWizardPage { wxRadioButton *radio_simple; @@ -455,6 +466,11 @@ struct ConfigWizard::priv PageMaterials *page_sla_materials = nullptr; PageCustom *page_custom = nullptr; PageUpdate *page_update = nullptr; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + PageReloadFromDisk *page_reload_from_disk = nullptr; +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ PageMode *page_mode = nullptr; PageVendors *page_vendors = nullptr; Pages3rdparty pages_3rdparty; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b0fb3f0e6..fe50466be 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4909,7 +4909,12 @@ void Plater::export_amf() wxBusyCursor wait; bool export_config = true; DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1"; + if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) { +#else if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Success p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path)); } else { @@ -4938,6 +4943,16 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); const std::string path_u8 = into_u8(path); wxBusyCursor wait; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1"; +#if ENABLE_THUMBNAIL_GENERATOR + ThumbnailData thumbnail_data; + p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true); + if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data)) { +#else + if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) { +#endif // ENABLE_THUMBNAIL_GENERATOR +#else #if ENABLE_THUMBNAIL_GENERATOR ThumbnailData thumbnail_data; p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true); @@ -4945,6 +4960,7 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) #else if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { #endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Success p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path)); p->set_project_filename(path); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 827d1f4e0..295c1a6ec 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -73,6 +73,16 @@ void PreferencesDialog::build() option = Option (def, "version_check"); m_optgroup->append_single_option_line(option); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + // Please keep in sync with ConfigWizard + def.label = L("Export sources full pathnames to 3mf and amf"); + def.type = coBool; + def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked."); + def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1")); + option = Option(def, "export_sources_full_pathnames"); + m_optgroup->append_single_option_line(option); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + // Please keep in sync with ConfigWizard def.label = L("Update built-in Presets automatically"); def.type = coBool; diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index b7eb12e02..28f8b54d5 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -363,10 +363,17 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx) ModelObject *model_object = model.add_object(); model_object->add_volume(*volumes[ivolume]); model_object->add_instance(); +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false)) { + boost::filesystem::remove(path_src); + throw std::runtime_error(L("Export of a temporary 3mf file failed")); + } +#else if (! Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr)) { boost::filesystem::remove(path_src); throw std::runtime_error(L("Export of a temporary 3mf file failed")); } +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF model.clear_objects(); model.clear_materials(); boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 5215e2ebd..5f1c74c36 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -51,7 +51,11 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { WHEN("model is saved+loaded to/from 3mf file") { // save the model to 3mf file std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf"; +#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF + store_3mf(test_file.c_str(), &src_model, nullptr, false); +#else store_3mf(test_file.c_str(), &src_model, nullptr); +#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // load back the model from the 3mf file Model dst_model; From 7a8251b62677b47baa0c9d0e9eb29ded3de0a95f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 8 Jan 2020 12:30:42 +0100 Subject: [PATCH 14/85] Attempt to fix #3479 --- src/slic3r/GUI/Mouse3DController.cpp | 15 +++++++++------ src/slic3r/GUI/Mouse3DController.hpp | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 38432d0d3..8485c4b27 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -631,13 +631,16 @@ bool Mouse3DController::connect_device() if (m_device != nullptr) { - std::vector manufacturer(1024, 0); - hid_get_manufacturer_string(m_device, manufacturer.data(), 1024); - m_device_str = boost::nowide::narrow(manufacturer.data()); + wchar_t buffer[1024]; + hid_get_manufacturer_string(m_device, buffer, 1024); + m_device_str = boost::nowide::narrow(buffer); + // #3479 seems to show that sometimes an extra whitespace is added, so we remove it + boost::algorithm::trim(m_device_str); - std::vector product(1024, 0); - hid_get_product_string(m_device, product.data(), 1024); - m_device_str += "/" + boost::nowide::narrow(product.data()); + hid_get_product_string(m_device, buffer, 1024); + m_device_str += "/" + boost::nowide::narrow(buffer); + // #3479 seems to show that sometimes an extra whitespace is added, so we remove it + boost::algorithm::trim(m_device_str); BOOST_LOG_TRIVIAL(info) << "Connected 3DConnexion device:"; BOOST_LOG_TRIVIAL(info) << "Manufacturer/product: " << m_device_str; diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index 3598d7df7..1cddf254b 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -68,7 +68,7 @@ class Mouse3DController CustomParameters m_translation_params; CustomParameters m_rotation_params; #if ENABLE_3DCONNEXION_Y_AS_ZOOM - CustomParameters m_zoom_params; + CustomParameters m_zoom_params; #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected. From e0811e4aa580983cc5316427414c46b9af7867d6 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 8 Jan 2020 14:58:12 +0100 Subject: [PATCH 15/85] Optimization of G-code export: 1) Don't allocate ExtruderOverrides if not necessary 2) Use boost::container::small_vectorfills.entities : layerm->perimeters.entities; - - for (const ExtrusionEntity *ee : source_entities) { - // fill represents infill extrusions of a single island. - const auto *fill = dynamic_cast(ee); - if (fill->entities.empty()) // This shouldn't happen but first_point() would fail. + std::vector printing_extruders; + for (const ObjectByExtruder::Island::Region::Type entity_type : { ObjectByExtruder::Island::Region::INFILL, ObjectByExtruder::Island::Region::PERIMETERS }) { + for (const ExtrusionEntity *ee : (entity_type == ObjectByExtruder::Island::Region::INFILL) ? layerm->fills.entities : layerm->perimeters.entities) { + // extrusions represents infill or perimeter extrusions of a single island. + assert(dynamic_cast(ee) != nullptr); + const auto *extrusions = static_cast(ee); + if (extrusions->entities.empty()) // This shouldn't happen but first_point() would fail. continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - int correct_extruder_id = Print::get_extruder(*fill, region); + int correct_extruder_id = Print::get_extruder(*extrusions, region); // Let's recover vector of extruder overrides: - const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->copies().size()); + const WipingExtrusions::ExtruderPerCopy *entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->copies().size()); + printing_extruders.clear(); + if (entity_overrides == nullptr) { + printing_extruders.emplace_back(correct_extruder_id); + } else { + printing_extruders.reserve(entity_overrides->size() + 1); + for (int extruder : *entity_overrides) + printing_extruders.emplace_back(extruder >= 0 ? + // at least one copy is overridden to use this extruder + extruder : + // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + static_cast(- extruder - 1)); + } + if (! layer_tools.has_extruder(correct_extruder_id)) { + // this entity is not overridden, but its extruder is not in layer_tools - we'll print it + // by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) + printing_extruders.emplace_back(layer_tools.extruders.back()); + } + Slic3r::sort_remove_duplicates(printing_extruders); + if (printing_extruders.size() == 1 && printing_extruders.front() == correct_extruder_id) + entity_overrides = nullptr; // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: - for (unsigned int extruder : layer_tools.extruders) + for (unsigned int extruder : printing_extruders) { - // Init by_extruder item only if we actually use the extruder: - if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder - std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end() || // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) - (std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder_id) == layer_tools.extruders.end() && extruder == layer_tools.extruders.back())) // this entity is not overridden, but its extruder is not in layer_tools - we'll print it - //by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) - { - std::vector &islands = object_islands_by_extruder( - by_extruder, - extruder, - &layer_to_print - layers.data(), - layers.size(), n_slices+1); - for (size_t i = 0; i <= n_slices; ++ i) { - bool last = i == n_slices; - size_t island_idx = last ? n_slices : slices_test_order[i]; - if (// fill->first_point does not fit inside any slice - last || - // fill->first_point fits inside ith slice - point_inside_surface(island_idx, fill->first_point())) { - if (islands[island_idx].by_region.empty()) - islands[island_idx].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region()); - islands[island_idx].by_region[region_id].append(entity_type, fill, entity_overrides, layer_to_print.object()->copies().size()); - break; - } + std::vector &islands = object_islands_by_extruder( + by_extruder, + extruder, + &layer_to_print - layers.data(), + layers.size(), n_slices+1); + for (size_t i = 0; i <= n_slices; ++ i) { + bool last = i == n_slices; + size_t island_idx = last ? n_slices : slices_test_order[i]; + if (// extrusions->first_point does not fit inside any slice + last || + // extrusions->first_point fits inside ith slice + point_inside_surface(island_idx, extrusions->first_point())) { + if (islands[island_idx].by_region.empty()) + islands[island_idx].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region()); + islands[island_idx].by_region[region_id].append(entity_type, extrusions, entity_overrides); + break; } } } @@ -2147,6 +2158,7 @@ void GCode::process_layer( // We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature): bool is_anything_overridden = const_cast(layer_tools).wiping_extrusions().is_anything_overridden(); + std::vector by_region_per_copy_cache; for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) { if (is_anything_overridden && print_wipe_extrusions == 0) gcode+="; PURGING FINISHED\n"; @@ -2174,8 +2186,8 @@ void GCode::process_layer( m_layer = layers[instance_to_print.layer_id].layer(); } for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) { - const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(instance_to_print.instance_id, extruder_id, print_wipe_extrusions) : island.by_region; - + const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, instance_to_print.instance_id, extruder_id, print_wipe_extrusions) : island.by_region; + //FIXME the following code prints regions in the order they are defined, the path is not optimized in any way. if (print.config().infill_first) { gcode += this->extrude_infill(print, by_region_specific); gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]); @@ -3260,59 +3272,97 @@ Point GCode::gcode_to_point(const Vec2d &point) const // Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed // during infill/perimeter wiping, or normally (depends on wiping_entities parameter) -// Returns a reference to member to avoid copying. -const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities) +// Fills in by_region_per_copy_cache and returns its reference. +const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities) const { + bool has_overrides = false; + for (const auto& reg : by_region) + if (! reg.infills_overrides.empty() || ! reg.perimeters_overrides.empty()) { + has_overrides = true; + break; + } + if (! has_overrides) + // Simple case. No need to copy the regions. + return this->by_region; + + // Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions. + // Some of the extrusions of some object instances are printed later - those are the clean print extrusions. + // Filter out the extrusions based on the infill_overrides / perimeter_overrides: + + // Data is cleared, but the memory is not. by_region_per_copy_cache.clear(); for (const auto& reg : by_region) { - by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); // creates a region in the newly created Island + by_region_per_copy_cache.emplace_back(); // creates a region in the newly created Island // Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed // References are used so that we don't have to repeat the same code for (int iter = 0; iter < 2; ++iter) { - const ExtrusionEntitiesPtr& entities = (iter ? reg.infills.entities : reg.perimeters.entities); - ExtrusionEntityCollection& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters); - const std::vector& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides); + const ExtrusionEntitiesPtr& entities = (iter ? reg.infills.entities : reg.perimeters.entities); + ExtrusionEntityCollection& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters); + const std::vector& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides); // Now the most important thing - which extrusion should we print. // See function ToolOrdering::get_extruder_overrides for details about the negative numbers hack. - int this_extruder_mark = wiping_entities ? extruder : -extruder-1; - - for (unsigned int i=0;iat(copy) == this_extruder_mark) // this copy should be printed with this extruder - target_eec.append((*entities[i])); + if (wiping_entities) { + // Apply overrides for this region. + for (unsigned int i = 0; i < overrides.size(); ++ i) { + const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; + // This copy (aka object instance) should be printed with this extruder, which overrides the default one. + if (this_override != nullptr && (*this_override)[copy] == extruder) + // Clone the ExtrusionEntity. This is quite expensive. + target_eec.append((*entities[i])); + } + } else { + // Apply normal extrusions (non-overrides) for this region. + unsigned int i = 0; + for (; i < overrides.size(); ++ i) { + const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; + // This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one. + if (this_override == nullptr || (*this_override)[copy] == -extruder-1) + // Clone the ExtrusionEntity. This is quite expensive. + target_eec.append((*entities[i])); + } + for (; i < overrides.size(); ++ i) + // Clone the ExtrusionEntity. This is quite expensive. + target_eec.append(*entities[i]); + } } } return by_region_per_copy_cache; } - - // This function takes the eec and appends its entities to either perimeters or infills of this Region (depending on the first parameter) // It also saves pointer to ExtruderPerCopy struct (for each entity), that holds information about which extruders should be used for which copy. -void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, size_t object_copies_num) +void GCode::ObjectByExtruder::Island::Region::append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copies_extruder) { // We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves: - ExtrusionEntityCollection* perimeters_or_infills = &infills; - std::vector* perimeters_or_infills_overrides = &infills_overrides; + ExtrusionEntityCollection* perimeters_or_infills; + std::vector* perimeters_or_infills_overrides; - if (type == "perimeters") { - perimeters_or_infills = &perimeters; - perimeters_or_infills_overrides = &perimeters_overrides; + switch (type) { + case PERIMETERS: + perimeters_or_infills = &perimeters; + perimeters_or_infills_overrides = &perimeters_overrides; + break; + case INFILL: + perimeters_or_infills = &infills; + perimeters_or_infills_overrides = &infills_overrides; + break; + default: + throw std::invalid_argument("Unknown parameter!"); } - else - if (type != "infills") { - throw std::invalid_argument("Unknown parameter!"); - return; - } - // First we append the entities, there are eec->entities.size() of them: + size_t old_size = perimeters_or_infills->entities.size(); perimeters_or_infills->append(eec->entities); - for (unsigned int i=0;ientities.size();++i) - perimeters_or_infills_overrides->push_back(copies_extruder); + if (copies_extruder != nullptr) { + perimeters_or_infills_overrides->reserve(old_size + eec->entities.size()); + perimeters_or_infills_overrides->resize(old_size, nullptr); + for (unsigned int i = 0; i < eec->entities.size(); ++ i) + perimeters_or_infills_overrides->emplace_back(copies_extruder); + } } } // namespace Slic3r diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 497dc8c71..934dcaece 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -239,7 +239,6 @@ protected: std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.); - typedef std::vector ExtruderPerCopy; // Extruding multiple objects with soluble / non-soluble / combined supports // on a multi-material printer, trying to minimize tool switches. // Following structures sort extrusions by the extruder ID, by an order of objects and object islands. @@ -256,18 +255,23 @@ protected: ExtrusionEntityCollection perimeters; ExtrusionEntityCollection infills; - std::vector infills_overrides; - std::vector perimeters_overrides; + std::vector infills_overrides; + std::vector perimeters_overrides; + + enum Type { + PERIMETERS, + INFILL, + }; // Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping - void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, size_t object_copies_num); + void append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copy_extruders); }; - std::vector by_region; // all extrusions for this island, grouped by regions - const std::vector& by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities = false); // returns reference to subvector of by_region - private: - std::vector by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating + std::vector by_region; // all extrusions for this island, grouped by regions + + // Fills in by_region_per_copy_cache and returns its reference. + const std::vector& by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities = false) const; }; std::vector islands; }; @@ -277,7 +281,9 @@ protected: InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) : object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {} - ObjectByExtruder &object_by_extruder; + // Repository + ObjectByExtruder &object_by_extruder; + // Index into std::vector, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances. const size_t layer_id; const PrintObject &print_object; // Instance idx of the copy of a print object. @@ -285,7 +291,8 @@ protected: }; std::vector sort_print_object_instances( - std::vector &objects_by_extruder, + std::vector &objects_by_extruder, + // Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances. const std::vector &layers, // Ordering must be defined for normal (non-sequential print). const std::vector> *ordering, diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index bcb65554d..123656e43 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -19,7 +19,7 @@ namespace Slic3r { // Returns true in case that extruder a comes before b (b does not have to be present). False otherwise. bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const { - if (a==b) + if (a == b) return false; for (auto extruder : extruders) { @@ -415,10 +415,9 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi { something_overridden = true; - auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; // (add and) return iterator - auto& copies_vector = entity_map_it->second; - if (copies_vector.size() < num_of_copies) - copies_vector.resize(num_of_copies, -1); + auto entity_map_it = (entity_map.emplace(entity, ExtruderPerCopy())).first; // (add and) return iterator + ExtruderPerCopy& copies_vector = entity_map_it->second; + copies_vector.resize(num_of_copies, -1); if (copies_vector[copy_id] != -1) std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen. @@ -426,7 +425,6 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi copies_vector[copy_id] = extruder; } - // Finds first non-soluble extruder on the layer int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const { @@ -622,31 +620,23 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) } } - - - - - - -// Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. -// It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy -// It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, -// so -1 was used as "print as usual". -// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, -// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). -const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies) +// Following function is called from GCode::process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. +// If this extrusion does not have any override, nullptr is returned. +// Otherwise it modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, +// so -1 was used as "print as usual"). +// The resulting vector therefore keeps track of which extrusions are the ones that were overridden and which were not. If the extruder used is overridden, +// its number is saved as is (zero-based index). Regular extrusions are saved as -number-1 (unfortunately there is no negative zero). +const WipingExtrusions::ExtruderPerCopy* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies) { + ExtruderPerCopy *overrides = nullptr; auto entity_map_it = entity_map.find(entity); - if (entity_map_it == entity_map.end()) - entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; - - // Now the entity_map_it should be valid, let's make sure the vector is long enough: - entity_map_it->second.resize(num_of_copies, -1); - - // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): - std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1); - - return &(entity_map_it->second); + if (entity_map_it != entity_map.end()) { + overrides = &entity_map_it->second; + overrides->resize(num_of_copies, -1); + // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): + std::replace(overrides->begin(), overrides->end(), -1, -correct_extruder_id-1); + } + return overrides; } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index c37c90823..dcb93c021 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -7,6 +7,8 @@ #include +#include + namespace Slic3r { class Print; @@ -25,8 +27,19 @@ public: return something_overridden; } + // When allocating extruder overrides of an object's ExtrusionEntity, overrides for maximum 3 copies are allocated in place. + typedef boost::container::small_vector ExtruderPerCopy; + + class ExtruderOverrides + { + public: + ExtruderOverrides(const ExtruderPerCopy *overrides, const int correct_extruder_id) : m_overrides(overrides) {} + private: + const ExtruderPerCopy *m_overrides; + }; + // This is called from GCode::process_layer - see implementation for further comments: - const std::vector* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies); + const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies); // This function goes through all infill entities, decides which ones will be used for wiping and // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: @@ -50,7 +63,7 @@ private: return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1); } - std::map> entity_map; // to keep track of who prints what + std::map entity_map; // to keep track of who prints what bool something_overridden = false; const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to }; @@ -74,6 +87,7 @@ public: bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; } bool is_extruder_order(unsigned int a, unsigned int b) const; + bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); } coordf_t print_z; bool has_object; diff --git a/src/libslic3r/pchheader.hpp b/src/libslic3r/pchheader.hpp index 67b3d3a21..1339368bd 100644 --- a/src/libslic3r/pchheader.hpp +++ b/src/libslic3r/pchheader.hpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include From 3e0690b37bff4af00015a3b393c39a129ab0d1cc Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 8 Jan 2020 15:16:31 +0100 Subject: [PATCH 16/85] Further optimizations of G-Code generator when Wipe into object / infill: Don't do unnecessary tests if it is known that there is no Wipe into object or infill active. --- src/libslic3r/GCode.cpp | 46 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1e7fae3b5..f5e075a36 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1947,6 +1947,7 @@ void GCode::process_layer( // Group extrusions by an extruder, then by an object, an island and a region. std::map> by_extruder; + bool is_anything_overridden = const_cast(layer_tools).wiping_extrusions().is_anything_overridden(); for (const LayerToPrint &layer_to_print : layers) { if (layer_to_print.support_layer != nullptr) { const SupportLayer &support_layer = *layer_to_print.support_layer; @@ -2048,27 +2049,29 @@ void GCode::process_layer( int correct_extruder_id = Print::get_extruder(*extrusions, region); // Let's recover vector of extruder overrides: - const WipingExtrusions::ExtruderPerCopy *entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->copies().size()); - printing_extruders.clear(); - if (entity_overrides == nullptr) { - printing_extruders.emplace_back(correct_extruder_id); - } else { - printing_extruders.reserve(entity_overrides->size() + 1); - for (int extruder : *entity_overrides) - printing_extruders.emplace_back(extruder >= 0 ? - // at least one copy is overridden to use this extruder - extruder : - // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) - static_cast(- extruder - 1)); - } - if (! layer_tools.has_extruder(correct_extruder_id)) { - // this entity is not overridden, but its extruder is not in layer_tools - we'll print it - // by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) - printing_extruders.emplace_back(layer_tools.extruders.back()); - } - Slic3r::sort_remove_duplicates(printing_extruders); - if (printing_extruders.size() == 1 && printing_extruders.front() == correct_extruder_id) - entity_overrides = nullptr; + const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr; + if (is_anything_overridden) { + printing_extruders.clear(); + if (! layer_tools.has_extruder(correct_extruder_id)) { + // this entity is not overridden, but its extruder is not in layer_tools - we'll print it + // by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) + correct_extruder_id = layer_tools.extruders.back(); + } + entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->copies().size()); + if (entity_overrides == nullptr) { + printing_extruders.emplace_back(correct_extruder_id); + } else { + printing_extruders.reserve(entity_overrides->size()); + for (int extruder : *entity_overrides) + printing_extruders.emplace_back(extruder >= 0 ? + // at least one copy is overridden to use this extruder + extruder : + // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + static_cast(- extruder - 1)); + } + Slic3r::sort_remove_duplicates(printing_extruders); + } else + printing_extruders = { correct_extruder_id }; // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: for (unsigned int extruder : printing_extruders) @@ -2157,7 +2160,6 @@ void GCode::process_layer( std::vector instances_to_print = sort_print_object_instances(objects_by_extruder_it->second, layers, ordering, single_object_instance_idx); // We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature): - bool is_anything_overridden = const_cast(layer_tools).wiping_extrusions().is_anything_overridden(); std::vector by_region_per_copy_cache; for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) { if (is_anything_overridden && print_wipe_extrusions == 0) From 07c1c3d1dc9aade0b95fa570314205ee8ee35481 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 8 Jan 2020 15:23:46 +0100 Subject: [PATCH 17/85] Fixed update of "Cost" field in "Sliced Info" box after a change of any material's options ("bottle_cost", "bottle_volume", "bottle_weight", "material_density") --- src/slic3r/GUI/Plater.cpp | 4 ++-- src/slic3r/GUI/Tab.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b0fb3f0e6..2c0742559 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1192,9 +1192,9 @@ void Sidebar::update_sliced_info_sizer() { double material_cost = cfg->option("bottle_cost")->getFloat() / cfg->option("bottle_volume")->getFloat(); - str_total_cost = wxString::Format("%.2f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); + str_total_cost = wxString::Format("%.3f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); } - p->sliced_info->SetTextAndShow(siCost, str_total_cost); + p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + " :"); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 353e822e3..c518ede80 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3448,7 +3448,7 @@ void TabSLAMaterial::build() new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); } if (opt_key == "bottle_weight") { - double new_bottle_volume = boost::any_cast(value)/(new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_volume = boost::any_cast(value)/new_conf.option("material_density")->getFloat() * 1000; new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { @@ -3459,12 +3459,10 @@ void TabSLAMaterial::build() load_config(new_conf); update_dirty(); - on_value_change(opt_key, value); - if (opt_key == "bottle_volume" || opt_key == "bottle_cost") { - wxGetApp().sidebar().update_sliced_info_sizer(); - wxGetApp().sidebar().Layout(); - } + // Change of any from those options influences for an update of "Sliced Info" + wxGetApp().sidebar().update_sliced_info_sizer(); + wxGetApp().sidebar().Layout(); }; optgroup = page->new_optgroup(_(L("Layers"))); From 3d4cda8ace890fcd0cc63951d7b0274dab50662f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 8 Jan 2020 15:23:46 +0100 Subject: [PATCH 18/85] Fixed update of "Cost" field in "Sliced Info" box after a change of any material's options ("bottle_cost", "bottle_volume", "bottle_weight", "material_density") --- src/slic3r/GUI/Plater.cpp | 4 ++-- src/slic3r/GUI/Tab.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index fe50466be..011d7e7ce 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1192,9 +1192,9 @@ void Sidebar::update_sliced_info_sizer() { double material_cost = cfg->option("bottle_cost")->getFloat() / cfg->option("bottle_volume")->getFloat(); - str_total_cost = wxString::Format("%.2f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); + str_total_cost = wxString::Format("%.3f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); } - p->sliced_info->SetTextAndShow(siCost, str_total_cost); + p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + " :"); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 353e822e3..c518ede80 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3448,7 +3448,7 @@ void TabSLAMaterial::build() new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); } if (opt_key == "bottle_weight") { - double new_bottle_volume = boost::any_cast(value)/(new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_volume = boost::any_cast(value)/new_conf.option("material_density")->getFloat() * 1000; new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { @@ -3459,12 +3459,10 @@ void TabSLAMaterial::build() load_config(new_conf); update_dirty(); - on_value_change(opt_key, value); - if (opt_key == "bottle_volume" || opt_key == "bottle_cost") { - wxGetApp().sidebar().update_sliced_info_sizer(); - wxGetApp().sidebar().Layout(); - } + // Change of any from those options influences for an update of "Sliced Info" + wxGetApp().sidebar().update_sliced_info_sizer(); + wxGetApp().sidebar().Layout(); }; optgroup = page->new_optgroup(_(L("Layers"))); From 0aaa7dd076fba27ca7e4f24575e288f92b90662c Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 8 Jan 2020 15:44:39 +0100 Subject: [PATCH 19/85] Small fix for https://github.com/prusa3d/PrusaSlicer/commit/3e0690b37bff4af00015a3b393c39a129ab0d1cc --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f5e075a36..3b2d2ca74 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2071,7 +2071,7 @@ void GCode::process_layer( } Slic3r::sort_remove_duplicates(printing_extruders); } else - printing_extruders = { correct_extruder_id }; + printing_extruders = { (unsigned int)correct_extruder_id }; // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: for (unsigned int extruder : printing_extruders) From fb65e3152f12faf6d515e8e1c184e00c9a42758b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 8 Jan 2020 15:26:01 +0100 Subject: [PATCH 20/85] DoubleSlider modes(states) are extended and implemented mode detection from model + Some code refactoring --- src/slic3r/GUI/GUI_Preview.cpp | 6 +++- src/slic3r/GUI/Plater.cpp | 32 ++++++++++++++++++++ src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 53 ++++++++++++++++++++++----------- src/slic3r/GUI/wxExtensions.hpp | 33 +++++--------------- 5 files changed, 82 insertions(+), 43 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 1a4d12d31..0c3138c80 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -692,7 +692,11 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); m_slider->EnableTickManipulation(color_print_enable); - m_slider->SetManipulationState(wxGetApp().extruders_edited_cnt()); + + // Detect and set manipulation mode for double slider + m_slider->SetManipulationState( wxGetApp().extruders_edited_cnt() == 1 ? DoubleSlider::msSingleExtruder : + wxGetApp().plater()->is_one_extruder_printed_model() ? DoubleSlider::msMultiAsSingle : + DoubleSlider::msMultiExtruder); } void Preview::reset_double_slider() diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2c0742559..01241bd8f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5358,6 +5358,38 @@ bool Plater::is_export_gcode_scheduled() const return p->background_process.is_export_scheduled(); } +bool Plater::is_one_extruder_printed_model() +{ + if (wxGetApp().extruders_edited_cnt() == 1) + return true; + + // check if model use just one extruder + const ModelObjectPtrs& objects = p->model.objects; + if (!objects.empty()) + { + const size_t extruder = objects[0]->config.has("extruder") ? + objects[0]->config.option("extruder")->getInt() : 0; + for (ModelObject* object : objects) + { + if (object->config.has("extruder") && + object->config.option("extruder")->getInt() != extruder) + return false; + + for (ModelVolume* volume : object->volumes) + if (volume->config.has("extruder") && + volume->config.option("extruder")->getInt() != extruder) + return false; + + for (const auto& range : object->layer_config_ranges) + if (range.second.has("extruder") && + range.second.option("extruder")->getInt() != extruder) + return false; + } + } + + return true; +} + int Plater::get_selected_object_idx() { return p->get_selected_object_idx(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 479397705..2c7e13e45 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -234,6 +234,7 @@ public: void set_project_filename(const wxString& filename); bool is_export_gcode_scheduled() const; + bool is_one_extruder_printed_model(); int get_selected_object_idx(); bool is_single_full_object_selection() const; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 7b36207f5..3f4d43b5b 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2861,13 +2861,13 @@ void DoubleSlider::draw_colored_band(wxDC& dc) const wxColour bg_clr = GetParent()->GetBackgroundColour(); - wxColour clr = m_state == msSingleExtruder ? wxColour(colors[0]) : bg_clr; + wxColour clr = m_ticks_.empty() ? bg_clr : wxColour(colors[0]); draw_band(dc, clr, main_band); size_t i = 1; for (auto tick : m_ticks_) { - if ( (m_state == msSingleExtruder && tick.gcode != Slic3r::ColorChangeCode) || + if ( (m_state != msMultiExtruder/*m_state == msSingleExtruder*/ && tick.gcode != Slic3r::ColorChangeCode) || (m_state == msMultiExtruder && tick.gcode != Slic3r::ExtruderChangeCode) ) continue; @@ -3182,31 +3182,50 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) if (m_show_context_menu) { - if (m_state == msMultiExtruder) + if (m_state == msSingleExtruder) + add_code(Slic3r::ColorChangeCode); + else { - wxMenu menu; const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); if (extruders_cnt > 1) - { - const int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); + { + wxMenu menu; + wxMenu* sub_menu = new wxMenu(); + wxString sub_menu_name = _(L("Change extruder")); + std::string menu_icon_name = "change_extruder"; - wxMenu* change_extruder_menu = new wxMenu(); + if (m_state == msMultiAsSingle) + { + int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); + if (initial_extruder == 0) + initial_extruder = 1; - for (int i = 0; i <= extruders_cnt; i++) { - const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i); + for (int i = /*0*/1; i <= extruders_cnt; i++) { + const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i); - append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder); + append_menu_radio_item(sub_menu, wxID_ANY, item_name, "", + [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder); + } + } + else + { + for (int i = 1; i <= extruders_cnt; i++) { + const wxString item_name = wxString::Format(_(L("Extruder %d")), i); + + append_menu_item(sub_menu, wxID_ANY, item_name, "", + [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu); + } + + sub_menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); + menu_icon_name = "colorchange_add_m"; } - wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, _(L("Change extruder")), _(L("Use another extruder"))); - change_extruder_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "change_extruder")); - } + wxMenuItem* sub_menu_item = menu.AppendSubMenu(sub_menu, sub_menu_name, ""); + sub_menu_item->SetBitmap(create_scaled_bitmap(this, menu_icon_name)); - Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); + Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); + } } - else - add_code(Slic3r::ColorChangeCode); m_show_context_menu = false; } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 390dafab9..31e60d7d6 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -823,7 +823,10 @@ public: enum ManipulationState { msSingleExtruder, // single extruder printer preset is selected - msMultiExtruder // multiple extruder printer preset is selected, and "Whole print" is selected + msMultiAsSingle, // multiple extruder printer preset is selected, but + // this mode works just for Single extruder print + // (For all print from objects settings is used just one extruder) + msMultiExtruder // multiple extruder printer preset is selected }; void SetManipulationState(ManipulationState state) { m_state = state; @@ -976,31 +979,11 @@ private: public: struct ExtrudersSequence { - bool is_mm_intervals; - double interval_by_mm; - int interval_by_layers; - std::vector extruders; + bool is_mm_intervals = true; + double interval_by_mm = 3.0; + int interval_by_layers = 10; + std::vector extruders = { 0 }; - ExtrudersSequence() : - is_mm_intervals(true), - interval_by_mm(3.0), - interval_by_layers(10), - extruders({ 0 }) {} - - ExtrudersSequence(const ExtrudersSequence& other) : - is_mm_intervals(other.is_mm_intervals), - interval_by_mm(other.interval_by_mm), - interval_by_layers(other.interval_by_layers), - extruders(other.extruders) {} - - ExtrudersSequence& operator=(const ExtrudersSequence& other) { - this->is_mm_intervals = other.is_mm_intervals; - this->interval_by_mm = other.interval_by_mm; - this->interval_by_layers= other.interval_by_layers; - this->extruders = other.extruders; - - return *this; - } bool operator==(const ExtrudersSequence& other) const { return (other.is_mm_intervals == this->is_mm_intervals ) && From de70adca9cd70f7243eeb5c8f186f88b481453a8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 9 Jan 2020 10:00:38 +0100 Subject: [PATCH 21/85] Optimization of G-code export: Don't make copies of ExtrusionEntities when sorting them into Extruders / Islands / Regions. --- src/libslic3r/ExtrusionEntityCollection.cpp | 32 ++++++++------------- src/libslic3r/ExtrusionEntityCollection.hpp | 4 ++- src/libslic3r/GCode.cpp | 27 ++++++++--------- src/libslic3r/GCode.hpp | 7 +++-- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index e1a9709d1..7e0e1fc9c 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -74,31 +74,23 @@ void ExtrusionEntityCollection::remove(size_t i) this->entities.erase(this->entities.begin() + i); } -ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const Point &start_near, ExtrusionRole role) const +ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const ExtrusionEntitiesPtr& extrusion_entities, const Point &start_near, ExtrusionRole role) { ExtrusionEntityCollection out; - if (this->no_sort) { - out = *this; - } else { - if (role == erMixed) - out = *this; - else { - for (const ExtrusionEntity *ee : this->entities) { - if (role != erMixed) { - // The caller wants only paths with a specific extrusion role. - auto role2 = ee->role(); - if (role != role2) { - // This extrusion entity does not match the role asked. - assert(role2 != erMixed); - continue; - } - } - out.entities.emplace_back(ee->clone()); + for (const ExtrusionEntity *ee : extrusion_entities) { + if (role != erMixed) { + // The caller wants only paths with a specific extrusion role. + auto role2 = ee->role(); + if (role != role2) { + // This extrusion entity does not match the role asked. + assert(role2 != erMixed); + continue; } } - chain_and_reorder_extrusion_entities(out.entities, &start_near); + out.entities.emplace_back(ee->clone()); } - return out; + chain_and_reorder_extrusion_entities(out.entities, &start_near); + return out; } void ExtrusionEntityCollection::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp index 3084e5741..e529bea02 100644 --- a/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/src/libslic3r/ExtrusionEntityCollection.hpp @@ -65,7 +65,9 @@ public: } void replace(size_t i, const ExtrusionEntity &entity); void remove(size_t i); - ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const; + static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed); + ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const + { return (this->no_sort || role == erMixed) ? *this : chained_path_from(this->entities, start_near, role); } void reverse(); const Point& first_point() const { return this->entities.front()->first_point(); } const Point& last_point() const { return this->entities.back()->last_point(); } diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3b2d2ca74..f6396e8f7 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2797,7 +2797,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vectorconfig()); - for (ExtrusionEntity *ee : region.perimeters.entities) + for (const ExtrusionEntity *ee : region.perimeters) gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid); } return gcode; @@ -2809,7 +2809,9 @@ std::string GCode::extrude_infill(const Print &print, const std::vectorconfig()); - for (ExtrusionEntity *fill : region.infills.chained_path_from(m_last_pos).entities) { +// for (ExtrusionEntity *fill : ExtrusionEntityCollection::chained_path_from(region.infills, m_last_pos).entities) { + // Don't sort the infills, they contain gap fill, which shall be extruded after normal fills. + for (const ExtrusionEntity *fill : region.infills) { auto *eec = dynamic_cast(fill); if (eec) { for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities) @@ -3300,8 +3302,8 @@ const std::vector& GCode::ObjectByExtru // Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed // References are used so that we don't have to repeat the same code for (int iter = 0; iter < 2; ++iter) { - const ExtrusionEntitiesPtr& entities = (iter ? reg.infills.entities : reg.perimeters.entities); - ExtrusionEntityCollection& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters); + const ExtrusionEntitiesPtr& entities = (iter ? reg.infills : reg.perimeters); + ExtrusionEntitiesPtr& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters); const std::vector& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides); // Now the most important thing - which extrusion should we print. @@ -3312,8 +3314,7 @@ const std::vector& GCode::ObjectByExtru const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; // This copy (aka object instance) should be printed with this extruder, which overrides the default one. if (this_override != nullptr && (*this_override)[copy] == extruder) - // Clone the ExtrusionEntity. This is quite expensive. - target_eec.append((*entities[i])); + target_eec.emplace_back(entities[i]); } } else { // Apply normal extrusions (non-overrides) for this region. @@ -3322,12 +3323,10 @@ const std::vector& GCode::ObjectByExtru const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; // This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one. if (this_override == nullptr || (*this_override)[copy] == -extruder-1) - // Clone the ExtrusionEntity. This is quite expensive. - target_eec.append((*entities[i])); + target_eec.emplace_back(entities[i]); } for (; i < overrides.size(); ++ i) - // Clone the ExtrusionEntity. This is quite expensive. - target_eec.append(*entities[i]); + target_eec.emplace_back(entities[i]); } } } @@ -3339,7 +3338,7 @@ const std::vector& GCode::ObjectByExtru void GCode::ObjectByExtruder::Island::Region::append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copies_extruder) { // We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves: - ExtrusionEntityCollection* perimeters_or_infills; + ExtrusionEntitiesPtr* perimeters_or_infills; std::vector* perimeters_or_infills_overrides; switch (type) { @@ -3356,8 +3355,10 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr } // First we append the entities, there are eec->entities.size() of them: - size_t old_size = perimeters_or_infills->entities.size(); - perimeters_or_infills->append(eec->entities); + size_t old_size = perimeters_or_infills->size(); + perimeters_or_infills->reserve(perimeters_or_infills->size() + eec->entities.size()); + for (auto* ee : eec->entities) + perimeters_or_infills->emplace_back(ee); if (copies_extruder != nullptr) { perimeters_or_infills_overrides->reserve(old_size + eec->entities.size()); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 934dcaece..e8bc88a29 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -252,8 +252,11 @@ protected: struct Island { struct Region { - ExtrusionEntityCollection perimeters; - ExtrusionEntityCollection infills; + // Non-owned references to LayerRegion::perimeters::entities + // std::vector would be better here, but there is no way in C++ to convert from std::vector std::vector without copying. + ExtrusionEntitiesPtr perimeters; + // Non-owned references to LayerRegion::fills::entities + ExtrusionEntitiesPtr infills; std::vector infills_overrides; std::vector perimeters_overrides; From 5bb9ba64c2760fc5832b0f733e40ee8de051015d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 9 Jan 2020 10:14:50 +0100 Subject: [PATCH 22/85] Fix of previous commit --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f6396e8f7..abfa87a75 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2812,7 +2812,7 @@ std::string GCode::extrude_infill(const Print &print, const std::vector(fill); + auto *eec = dynamic_cast(fill); if (eec) { for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities) gcode += this->extrude_entity(*ee, "infill"); From 051fcd4e2459cb23df9e99e4b8465c9e6bee5402 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 9 Jan 2020 10:27:42 +0100 Subject: [PATCH 23/85] Configurable system printers bed textures and models --- resources/profiles/Creality.ini | 2 + .../bed => profiles/Creality}/ender3.svg | 0 .../Creality}/ender3_bed.stl | Bin resources/profiles/PrusaResearch.ini | 24 ++++ .../bed => profiles/PrusaResearch}/mini.svg | 0 .../PrusaResearch}/mini_bed.stl | Bin .../bed => profiles/PrusaResearch}/mk2.svg | 0 .../PrusaResearch}/mk2_bed.stl | Bin .../bed => profiles/PrusaResearch}/mk3.svg | 0 .../PrusaResearch}/mk3_bed.stl | Bin .../bed => profiles/PrusaResearch}/sl1.svg | 0 .../PrusaResearch}/sl1_bed.stl | Bin src/slic3r/GUI/3DBed.cpp | 129 +++++++----------- src/slic3r/GUI/3DBed.hpp | 23 ++-- 14 files changed, 83 insertions(+), 95 deletions(-) rename resources/{icons/bed => profiles/Creality}/ender3.svg (100%) rename resources/{models => profiles/Creality}/ender3_bed.stl (100%) rename resources/{icons/bed => profiles/PrusaResearch}/mini.svg (100%) rename resources/{models => profiles/PrusaResearch}/mini_bed.stl (100%) rename resources/{icons/bed => profiles/PrusaResearch}/mk2.svg (100%) rename resources/{models => profiles/PrusaResearch}/mk2_bed.stl (100%) rename resources/{icons/bed => profiles/PrusaResearch}/mk3.svg (100%) rename resources/{models => profiles/PrusaResearch}/mk3_bed.stl (100%) rename resources/{icons/bed => profiles/PrusaResearch}/sl1.svg (100%) rename resources/{models => profiles/PrusaResearch}/sl1_bed.stl (100%) diff --git a/resources/profiles/Creality.ini b/resources/profiles/Creality.ini index 4ebf99d32..e9cac0e82 100644 --- a/resources/profiles/Creality.ini +++ b/resources/profiles/Creality.ini @@ -18,6 +18,8 @@ config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/Prusa name = Creality Ender-3 variants = 0.4 technology = FFF +bed_model = ender3_bed.stl +bed_texture = ender3.svg # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. diff --git a/resources/icons/bed/ender3.svg b/resources/profiles/Creality/ender3.svg similarity index 100% rename from resources/icons/bed/ender3.svg rename to resources/profiles/Creality/ender3.svg diff --git a/resources/models/ender3_bed.stl b/resources/profiles/Creality/ender3_bed.stl similarity index 100% rename from resources/models/ender3_bed.stl rename to resources/profiles/Creality/ender3_bed.stl diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 746aaf966..96b4369c5 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -22,72 +22,96 @@ name = Original Prusa MINI variants = 0.4; 0.25; 0.6 technology = FFF family = MINI +bed_model = mini_bed.stl +bed_texture = mini.svg [printer_model:MK3S] name = Original Prusa i3 MK3S variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK3] name = Original Prusa i3 MK3 variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK3SMMU2S] name = Original Prusa i3 MK3S MMU2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK3MMU2] name = Original Prusa i3 MK3 MMU2 variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK2.5S] name = Original Prusa i3 MK2.5S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK2.5] name = Original Prusa i3 MK2.5 variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK2.5SMMU2S] name = Original Prusa i3 MK2.5S MMU2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK2.5MMU2] name = Original Prusa i3 MK2.5 MMU2 variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +bed_model = mk3_bed.stl +bed_texture = mk3.svg [printer_model:MK2S] name = Original Prusa i3 MK2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2 +bed_model = mk2_bed.stl +bed_texture = mk2.svg [printer_model:MK2SMM] name = Original Prusa i3 MK2S MMU1 variants = 0.4; 0.6 technology = FFF family = MK2 +bed_model = mk2_bed.stl +bed_texture = mk2.svg [printer_model:SL1] name = Original Prusa SL1 variants = default technology = SLA family = SL1 +bed_model = sl1_bed.stl +bed_texture = sl1.svg # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. diff --git a/resources/icons/bed/mini.svg b/resources/profiles/PrusaResearch/mini.svg similarity index 100% rename from resources/icons/bed/mini.svg rename to resources/profiles/PrusaResearch/mini.svg diff --git a/resources/models/mini_bed.stl b/resources/profiles/PrusaResearch/mini_bed.stl similarity index 100% rename from resources/models/mini_bed.stl rename to resources/profiles/PrusaResearch/mini_bed.stl diff --git a/resources/icons/bed/mk2.svg b/resources/profiles/PrusaResearch/mk2.svg similarity index 100% rename from resources/icons/bed/mk2.svg rename to resources/profiles/PrusaResearch/mk2.svg diff --git a/resources/models/mk2_bed.stl b/resources/profiles/PrusaResearch/mk2_bed.stl similarity index 100% rename from resources/models/mk2_bed.stl rename to resources/profiles/PrusaResearch/mk2_bed.stl diff --git a/resources/icons/bed/mk3.svg b/resources/profiles/PrusaResearch/mk3.svg similarity index 100% rename from resources/icons/bed/mk3.svg rename to resources/profiles/PrusaResearch/mk3.svg diff --git a/resources/models/mk3_bed.stl b/resources/profiles/PrusaResearch/mk3_bed.stl similarity index 100% rename from resources/models/mk3_bed.stl rename to resources/profiles/PrusaResearch/mk3_bed.stl diff --git a/resources/icons/bed/sl1.svg b/resources/profiles/PrusaResearch/sl1.svg similarity index 100% rename from resources/icons/bed/sl1.svg rename to resources/profiles/PrusaResearch/sl1.svg diff --git a/resources/models/sl1_bed.stl b/resources/profiles/PrusaResearch/sl1_bed.stl similarity index 100% rename from resources/models/sl1_bed.stl rename to resources/profiles/PrusaResearch/sl1_bed.stl diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index ecbca4228..9e32df783 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -189,8 +189,6 @@ void Bed3D::Axes::render_axis(double length) const Bed3D::Bed3D() : m_type(Custom) - , m_custom_texture("") - , m_custom_model("") , m_vbo_id(0) , m_scale_factor(1.0f) { @@ -198,31 +196,31 @@ Bed3D::Bed3D() bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model) { - EType new_type = detect_type(shape); + auto check_texture = [](const std::string& texture) { + return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture); + }; - // check that the passed custom texture filename is valid - std::string cst_texture(custom_texture); - if (!cst_texture.empty()) - { - if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture)) - cst_texture = ""; - } + auto check_model = [](const std::string& model) { + return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model); + }; - // check that the passed custom texture filename is valid - std::string cst_model(custom_model); - if (!cst_model.empty()) - { - if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model)) - cst_model = ""; - } + auto [new_type, system_model, system_texture] = detect_type(shape); - if ((m_shape == shape) && (m_type == new_type) && (m_custom_texture == cst_texture) && (m_custom_model == cst_model)) + std::string texture_filename = custom_texture.empty() ? system_texture : custom_texture; + if (!check_texture(texture_filename)) + texture_filename.clear(); + + std::string model_filename = custom_model.empty() ? system_model : custom_model; + if (!check_model(model_filename)) + model_filename.clear(); + + if ((m_shape == shape) && (m_type == new_type) && (m_texture_filename == texture_filename) && (m_model_filename == model_filename)) // No change, no need to update the UI. return false; m_shape = shape; - m_custom_texture = cst_texture; - m_custom_model = cst_model; + m_texture_filename = texture_filename; + m_model_filename = model_filename; m_type = new_type; calc_bounding_boxes(); @@ -244,7 +242,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c m_texture.reset(); m_model.reset(); - // Set the origin and size for painting of the coordinate system axes. + // Set the origin and size for rendering the coordinate system axes. m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); @@ -273,11 +271,7 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho switch (m_type) { - case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; } - case MK3: { render_prusa(canvas, "mk3", theta > 90.0f); break; } - case SL1: { render_prusa(canvas, "sl1", theta > 90.0f); break; } - case MINI: { render_prusa(canvas, "mini", theta > 90.0f); break; } - case ENDER3: { render_prusa(canvas, "ender3", theta > 90.0f); break; } + case System: { render_system(canvas, theta > 90.0f); break; } default: case Custom: { render_custom(canvas, theta > 90.0f); break; } } @@ -373,10 +367,8 @@ static std::string system_print_bed_texture(const Preset &preset) return out; } -Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const +std::tuple Bed3D::detect_type(const Pointfs& shape) const { - EType type = Custom; - auto bundle = wxGetApp().preset_bundle; if (bundle != nullptr) { @@ -385,39 +377,12 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const { if (curr->config.has("bed_shape")) { - if (curr->vendor != nullptr) + if (shape == dynamic_cast(curr->config.option("bed_shape"))->values) { - if ((curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) - { - if (boost::contains(curr->name, "SL1")) - { - type = SL1; - break; - } - else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) - { - type = MK3; - break; - } - else if (boost::contains(curr->name, "MK2")) - { - type = MK2; - break; - } - else if (boost::contains(curr->name, "MINI")) - { - type = MINI; - break; - } - } - else if ((curr->vendor->name == "Creality") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) - { - if (boost::contains(curr->name, "ENDER-3")) - { - type = ENDER3; - break; - } - } + std::string model_filename = system_print_bed_model(*curr); + std::string texture_filename = system_print_bed_texture(*curr); + if (!model_filename.empty() && !texture_filename.empty()) + return std::make_tuple(System, model_filename, texture_filename); } } @@ -425,7 +390,7 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const } } - return type; + return std::make_tuple(Custom, "", ""); } void Bed3D::render_axes() const @@ -434,35 +399,35 @@ void Bed3D::render_axes() const m_axes.render(); } -void Bed3D::render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const +void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const { if (!bottom) - render_model(m_custom_model.empty() ? resources_dir() + "/models/" + key + "_bed.stl" : m_custom_model); + render_model(); - render_texture(m_custom_texture.empty() ? resources_dir() + "/icons/bed/" + key + ".svg" : m_custom_texture, bottom, canvas); + render_texture(bottom, canvas); } -void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const +void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const { - if (filename.empty()) + if (m_texture_filename.empty()) { m_texture.reset(); render_default(bottom); return; } - if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) + if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename)) { m_texture.reset(); - if (boost::algorithm::iends_with(filename, ".svg")) + if (boost::algorithm::iends_with(m_texture_filename, ".svg")) { // use higher resolution images if graphic card and opengl version allow GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); - if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename)) + if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) { // generate a temporary lower resolution texture to show while no main texture levels have been compressed - if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8)) + if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) { render_default(bottom); return; @@ -471,18 +436,18 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& } // starts generating the main texture, compression will run asynchronously - if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size)) + if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) { render_default(bottom); return; } } - else if (boost::algorithm::iends_with(filename, ".png")) + else if (boost::algorithm::iends_with(m_texture_filename, ".png")) { // generate a temporary lower resolution texture to show while no main texture levels have been compressed - if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename)) + if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) { - if (!m_temp_texture.load_from_file(filename, false, GLTexture::None, false)) + if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false)) { render_default(bottom); return; @@ -491,7 +456,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& } // starts generating the main texture, compression will run asynchronously - if (!m_texture.load_from_file(filename, true, GLTexture::MultiThreaded, true)) + if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) { render_default(bottom); return; @@ -590,12 +555,12 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& } } -void Bed3D::render_model(const std::string& filename) const +void Bed3D::render_model() const { - if (filename.empty()) + if (m_model_filename.empty()) return; - if ((m_model.get_filename() != filename) && m_model.init_from_file(filename)) + if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename)) { // move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad Vec3d shift = m_bounding_box.center(); @@ -616,16 +581,16 @@ void Bed3D::render_model(const std::string& filename) const void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const { - if (m_custom_texture.empty() && m_custom_model.empty()) + if (m_texture_filename.empty() && m_model_filename.empty()) { render_default(bottom); return; } if (!bottom) - render_model(m_custom_model); + render_model(); - render_texture(m_custom_texture, bottom, canvas); + render_texture(bottom, canvas); } void Bed3D::render_default(bool bottom) const diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index cd2de862e..b1640000d 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -5,6 +5,8 @@ #include "3DScene.hpp" #include "GLShader.hpp" +#include + class GLUquadric; typedef class GLUquadric GLUquadricObj; @@ -64,11 +66,7 @@ class Bed3D public: enum EType : unsigned char { - MK2, - MK3, - SL1, - MINI, - ENDER3, + System, Custom, Num_Types }; @@ -76,19 +74,19 @@ public: private: EType m_type; Pointfs m_shape; - std::string m_custom_texture; - std::string m_custom_model; + std::string m_texture_filename; + std::string m_model_filename; mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_extended_bounding_box; Polygon m_polygon; GeometryBuffer m_triangles; GeometryBuffer m_gridlines; mutable GLTexture m_texture; + mutable GLBed m_model; // temporary texture shown until the main texture has still no levels compressed mutable GLTexture m_temp_texture; mutable Shader m_shader; mutable unsigned int m_vbo_id; - mutable GLBed m_model; Axes m_axes; mutable float m_scale_factor; @@ -99,7 +97,6 @@ public: EType get_type() const { return m_type; } - bool is_prusa() const { return (m_type == MK2) || (m_type == MK3) || (m_type == SL1); } bool is_custom() const { return m_type == Custom; } const Pointfs& get_shape() const { return m_shape; } @@ -116,11 +113,11 @@ private: void calc_bounding_boxes() const; void calc_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); - EType detect_type(const Pointfs& shape) const; + std::tuple detect_type(const Pointfs& shape) const; void render_axes() const; - void render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const; - void render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const; - void render_model(const std::string& filename) const; + void render_system(GLCanvas3D& canvas, bool bottom) const; + void render_texture(bool bottom, GLCanvas3D& canvas) const; + void render_model() const; void render_custom(GLCanvas3D& canvas, bool bottom) const; void render_default(bool bottom) const; void reset(); From 63f8fda61d7222ca2e93aad8e47d32025e701ac5 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 9 Jan 2020 12:23:17 +0100 Subject: [PATCH 24/85] #3492 - Fix of export of toolpaths to obj --- src/slic3r/GUI/3DScene.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index bbfcabd36..f6b1719db 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -877,13 +877,10 @@ bool can_export_to_obj(const GLVolume& volume) if (!volume.is_active || !volume.is_extrusion_path) return false; - if (volume.indexed_vertex_array.triangle_indices.empty() && (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) == 0)) - return false; + bool has_triangles = !volume.indexed_vertex_array.triangle_indices.empty() || (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) > 0); + bool has_quads = !volume.indexed_vertex_array.quad_indices.empty() || (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) > 0); - if (volume.indexed_vertex_array.quad_indices.empty() && (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) == 0)) - return false; - - return true; + return has_triangles || has_quads; } bool GLVolumeCollection::has_toolpaths_to_export() const From 7fd4800e7cbee720f735e22848fdc05960e5435f Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 9 Jan 2020 14:21:01 +0100 Subject: [PATCH 25/85] Fix wrong bounding box calculation for initial arrange item. --- src/libnest2d/include/libnest2d/placers/nfpplacer.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 003028758..e44e1dae1 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -1116,12 +1116,8 @@ private: for(Item& item : items_) item.translate(d); } - void setInitialPosition(Item& item) { - auto sh = item.rawShape(); - sl::translate(sh, item.translation()); - sl::rotate(sh, item.rotation()); - - Box bb = sl::boundingBox(sh); + void setInitialPosition(Item& item) { + Box bb = item.boundingBox(); Vertex ci, cb; auto bbin = sl::boundingBox(bin_); From aed277089beaaec1a7a5a9936d0ba309f7057b21 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 9 Jan 2020 16:38:59 +0100 Subject: [PATCH 26/85] Updated tooltips and context menus for 3 manipulation mode of DoubleSlider + Some code refactoring --- src/slic3r/GUI/GUI_Preview.cpp | 6 +- src/slic3r/GUI/wxExtensions.cpp | 280 ++++++++++++++++++++++---------- src/slic3r/GUI/wxExtensions.hpp | 50 +++--- 3 files changed, 220 insertions(+), 116 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 0c3138c80..acb5c89e3 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -694,9 +694,9 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee m_slider->EnableTickManipulation(color_print_enable); // Detect and set manipulation mode for double slider - m_slider->SetManipulationState( wxGetApp().extruders_edited_cnt() == 1 ? DoubleSlider::msSingleExtruder : - wxGetApp().plater()->is_one_extruder_printed_model() ? DoubleSlider::msMultiAsSingle : - DoubleSlider::msMultiExtruder); + m_slider->SetManipulationMode( wxGetApp().extruders_edited_cnt() == 1 ? DoubleSlider::mmSingleExtruder : + wxGetApp().plater()->is_one_extruder_printed_model() ? DoubleSlider::mmMultiAsSingle : + DoubleSlider::mmMultiExtruder); } void Preview::reset_double_slider() diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 3f4d43b5b..8ccf605f5 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2561,7 +2561,7 @@ std::vector DoubleSlider::GetTicksValues() const const int val_size = m_values.size(); if (!m_values.empty()) - for (const TICK_CODE& tick : m_ticks_) { + for (const TICK_CODE& tick : m_ticks) { if (tick.tick > val_size) break; values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color}); @@ -2575,19 +2575,19 @@ void DoubleSlider::SetTicksValues(const std::vector& heights) if (m_values.empty()) return; - const bool was_empty = m_ticks_.empty(); + const bool was_empty = m_ticks.empty(); - m_ticks_.clear(); + m_ticks.clear(); for (auto h : heights) { auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon()); if (it == m_values.end()) continue; - m_ticks_.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); + m_ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); } - if (!was_empty && m_ticks_.empty()) + if (!was_empty && m_ticks.empty()) // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); @@ -2638,11 +2638,6 @@ void DoubleSlider::render() // draw line draw_scroll_line(dc, lower_pos, higher_pos); -// //lower slider: -// draw_thumb(dc, lower_pos, ssLower); -// //higher slider: -// draw_thumb(dc, higher_pos, ssHigher); - //draw color print ticks draw_ticks(dc); @@ -2668,7 +2663,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin return; wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); - if (m_ticks_.find(TICK_CODE{tick}) != m_ticks_.end()) + if (m_ticks.find(TICK_CODE{tick}) != m_ticks.end()) icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); wxCoord x_draw, y_draw; @@ -2811,7 +2806,7 @@ void DoubleSlider::draw_ticks(wxDC& dc) int height, width; get_size(&width, &height); const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width; - for (auto tick : m_ticks_) + for (auto tick : m_ticks) { const wxCoord pos = get_position_from_value(tick.tick); @@ -2834,6 +2829,96 @@ void DoubleSlider::draw_ticks(wxDC& dc) } } +bool DoubleSlider::get_color_for_tick(wxColour& color, std::set::const_iterator tick_it, const std::vector& colors) const +{ + if (m_mode == mmMultiExtruder) + { + color = GetParent()->GetBackgroundColour(); + return true; + } + + const std::string& code = tick_it->gcode; + if ( code == Slic3r::PausePrintCode || + (code != Slic3r::ColorChangeCode && code != Slic3r::ExtruderChangeCode) ) + return false; + + if (m_mode == mmSingleExtruder) { + if (code == Slic3r::ColorChangeCode) { + color = wxColour(tick_it->color); + return true; + } + return false; + } + + const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); + const int colors_cnt = colors.size(); + + auto get_m600_color_idx = [extruders_cnt, colors_cnt](const std::set& ticks, std::set::const_iterator it) + { + int shift = 0; + while (it != ticks.begin()) { + --it; + if (it->gcode == Slic3r::ColorChangeCode) + shift++; + } + + if (extruders_cnt + shift >= colors_cnt) + return 0; + return extruders_cnt + shift; + }; + + auto get_color_idx_for_tool_change = [extruders_cnt, colors_cnt, get_m600_color_idx](const std::set& ticks, std::set::const_iterator it) + { + const int current_extruder = it->extruder == 0 ? 1 : it->extruder; + if (extruders_cnt == colors_cnt) // there is no one "M600" + return std::min(extruders_cnt - 1, std::max(current_extruder - 1, 0)); + + auto it_n = it; + while (it_n != ticks.begin()) { + --it_n; + if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder) + return get_m600_color_idx(ticks, it_n); + } + + return std::min(extruders_cnt - 1, std::max(current_extruder - 1, 0)); + }; + + auto get_color_idx_for_color_change = [get_m600_color_idx](const std::set& ticks, std::set::const_iterator it) + { + auto it_n = it; + bool is_tool_change = false; + while (it_n != ticks.begin()) { + --it_n; + if (it_n->gcode == Slic3r::ExtruderChangeCode) { + is_tool_change = true; + if (it_n->extruder == it->extruder) + return get_m600_color_idx(ticks, it); + break; + } + } + if (!is_tool_change && it->extruder == 0) // use correct extruder number instead of 0 + return get_m600_color_idx(ticks, it); + + return -1; + }; + + // change tool (extruder) + if (code == Slic3r::ExtruderChangeCode) + color = wxColour(colors[get_color_idx_for_tool_change(m_ticks, tick_it)]); + + // change color for current extruder + if (code == Slic3r::ColorChangeCode) { + const int color_idx = get_color_idx_for_color_change(m_ticks, tick_it); + if (color_idx < 0) + return false; + if (color_idx >= colors_cnt) + return false; + color = wxColour(colors[color_idx]); + } + + return true; +} + void DoubleSlider::draw_colored_band(wxDC& dc) { if (!m_is_enabled_tick_manipulation) @@ -2856,29 +2941,40 @@ void DoubleSlider::draw_colored_band(wxDC& dc) dc.DrawRectangle(band_rc); }; - const std::vector& colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - int colors_cnt = colors.size(); + const std::vector& colors = Slic3r::GUI::wxGetApp().plater()->get_colors_for_color_print(); const wxColour bg_clr = GetParent()->GetBackgroundColour(); - wxColour clr = m_ticks_.empty() ? bg_clr : wxColour(colors[0]); + wxColour clr = m_ticks.empty() || m_mode == mmMultiExtruder ? bg_clr : wxColour(colors[0]); draw_band(dc, clr, main_band); - size_t i = 1; - for (auto tick : m_ticks_) - { - if ( (m_state != msMultiExtruder/*m_state == msSingleExtruder*/ && tick.gcode != Slic3r::ColorChangeCode) || - (m_state == msMultiExtruder && tick.gcode != Slic3r::ExtruderChangeCode) ) - continue; + if (m_ticks.empty() || m_mode == mmMultiExtruder) + // don't color a band for MultiExtruder mode + return; - const wxCoord pos = get_position_from_value(tick.tick); + std::set::const_iterator tick_it = m_ticks.begin(); + + while (tick_it != m_ticks.end()) + { + if ( (m_mode == mmSingleExtruder && tick_it->gcode != Slic3r::ColorChangeCode ) || + (m_mode == mmMultiAsSingle && !(tick_it->gcode == Slic3r::ExtruderChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) + { + ++tick_it; + continue; + } + + const wxCoord pos = get_position_from_value(tick_it->tick); is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) : main_band.SetBottom(pos - 1); - clr = (m_state == msMultiExtruder && tick.color.empty()) ? bg_clr : - m_state == msMultiExtruder ? wxColour(colors[std::min(colors_cnt - 1, tick.extruder-1)]) : wxColour(tick.color); + if (!get_color_for_tick(clr, tick_it, colors)) + { + ++tick_it; + continue; + } + draw_band(dc, clr, main_band); - i++; + ++tick_it; } } @@ -2903,7 +2999,7 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc) void DoubleSlider::draw_revert_icon(wxDC& dc) { - if (m_ticks_.empty() || !m_is_enabled_tick_manipulation) + if (m_ticks.empty() || !m_is_enabled_tick_manipulation) return; int width, height; @@ -2921,7 +3017,7 @@ void DoubleSlider::draw_revert_icon(wxDC& dc) void DoubleSlider::draw_cog_icon(wxDC& dc) { - if (m_state != msMultiExtruder) + if (m_mode != mmMultiExtruder) return; int width, height; @@ -2965,15 +3061,13 @@ void DoubleSlider::detect_selected_slider(const wxPoint& pt) bool DoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect) { - if (rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() && - rect.GetTop() <= pt.y && pt.y <= rect.GetBottom()) - return true; - return false; + return rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() && + rect.GetTop() <= pt.y && pt.y <= rect.GetBottom(); } int DoubleSlider::is_point_near_tick(const wxPoint& pt) { - for (auto tick : m_ticks_) { + for (auto tick : m_ticks) { const wxCoord pos = get_position_from_value(tick.tick); if (is_horizontal()) { @@ -3034,10 +3128,10 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) m_selection == ssLower ? correct_lower_value() : correct_higher_value(); if (!m_selection) m_selection = ssHigher; - m_ticks_.clear(); + m_ticks.clear(); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } - else if (is_point_in_rect(pos, m_rect_cog_icon) && m_state == msMultiExtruder) { + else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == mmMultiExtruder) { // show dialog for set extruder sequence m_edit_extruder_sequence = true; } @@ -3107,17 +3201,18 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus) else if (m_is_action_icon_focesed) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - const auto tick_code_it = m_ticks_.find(TICK_CODE{tick}); - tooltip = tick_code_it == m_ticks_.end() ? (m_state == msSingleExtruder ? - _(L("For add color change use left mouse button click")) : - _(L("For add change extruder use left mouse button click"))) + "\n" + - _(L("For add another code use right mouse button click")) : - tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_state == msSingleExtruder ? + const auto tick_code_it = m_ticks.find(TICK_CODE{tick}); + tooltip = tick_code_it == m_ticks.end() ? (m_mode == mmMultiAsSingle ? + _(L("For add change extruder use left mouse button click")) : + _(L("For add color change use left mouse button click")) ) + "\n" + + _(L("For add another code use right mouse button click")) : + tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_mode == mmSingleExtruder ? _(L("For Delete color change use left mouse button click\n" "For Edit color use right mouse button click")) : from_u8((boost::format(_utf8(L("Delete color change for Extruder %1%"))) % tick_code_it->extruder).str()) ): -// tick_code_it->gcode == Slic3r::PausePrintCode ? _(L("Delete pause")) : - tick_code_it->gcode == Slic3r::ExtruderChangeCode ? + tick_code_it->gcode == Slic3r::PausePrintCode ? + _(L("Delete pause")) : + tick_code_it->gcode == Slic3r::ExtruderChangeCode ? from_u8((boost::format(_utf8(L("Delete extruder change to \"%1%\""))) % tick_code_it->extruder).str()) : from_u8((boost::format(_utf8(L("For Delete \"%1%\" code use left mouse button click\n" "For Edit \"%1%\" code use right mouse button click"))) % tick_code_it->gcode ).str()); @@ -3138,7 +3233,7 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) if (!m_is_left_down && !m_is_one_layer) { m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action); - if (!m_ticks_.empty() && is_point_in_rect(pos, m_rect_revert_icon)) + if (!m_ticks.empty() && is_point_in_rect(pos, m_rect_revert_icon)) icon_focus = ifRevert; else if (is_point_in_rect(pos, m_rect_cog_icon)) icon_focus = ifCog; @@ -3182,7 +3277,7 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) if (m_show_context_menu) { - if (m_state == msSingleExtruder) + if (m_mode == mmSingleExtruder) add_code(Slic3r::ColorChangeCode); else { @@ -3194,7 +3289,7 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) wxString sub_menu_name = _(L("Change extruder")); std::string menu_icon_name = "change_extruder"; - if (m_state == msMultiAsSingle) + if (m_mode == mmMultiAsSingle) { int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); if (initial_extruder == 0) @@ -3213,7 +3308,8 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) const wxString item_name = wxString::Format(_(L("Extruder %d")), i); append_menu_item(sub_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu); + [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu, + [this]() {return true; }, this); } sub_menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); @@ -3285,13 +3381,13 @@ void DoubleSlider::action_tick(const TicksAction action) const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - const auto it = m_ticks_.find(TICK_CODE{tick}); + const auto it = m_ticks.find(TICK_CODE{tick}); - if (it != m_ticks_.end()) // erase this tick + if (it != m_ticks.end()) // erase this tick { if (action == taAdd) return; - m_ticks_.erase(TICK_CODE{tick}); + m_ticks.erase(TICK_CODE{tick}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3308,7 +3404,7 @@ void DoubleSlider::action_tick(const TicksAction action) if (m_suppress_add_code) return; m_suppress_add_code = true; - if (m_state != msMultiExtruder) + if (m_mode == mmSingleExtruder) // if (m_mode != mmMultiExtruder) add_code(Slic3r::ColorChangeCode); m_suppress_add_code = false; return; @@ -3395,8 +3491,8 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick - auto it = m_ticks_.find(TICK_CODE{ tick }); - if (it == m_ticks_.end()) + auto it = m_ticks.find(TICK_CODE{ tick }); + if (it == m_ticks.end()) { // show context menu on OnRightUp() m_show_context_menu = true; @@ -3429,11 +3525,11 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) int DoubleSlider::get_extruder_for_tick(int tick) { - if (m_ticks_.empty()) + if (m_ticks.empty()) return 0; - auto it = m_ticks_.lower_bound(TICK_CODE{tick}); - while (it != m_ticks_.begin()) { + auto it = m_ticks.lower_bound(TICK_CODE{tick}); + while (it != m_ticks.begin()) { --it; if(it->gcode == Slic3r::ExtruderChangeCode) return it->extruder; @@ -3452,45 +3548,57 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) if (m_show_context_menu) { wxMenu menu; - if (m_state == msMultiExtruder) + if (m_mode == mmSingleExtruder) + append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", + [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu, + [](){return true;}, this); + else { const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); if (extruders_cnt > 1) { - const int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); + int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); + if (initial_extruder == 0) + initial_extruder = 1; wxMenu* change_extruder_menu = new wxMenu(); wxMenu* add_color_change_menu = new wxMenu(); - for (int i = 0; i <= extruders_cnt; i++) { - const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i); + for (int i = 1; i <= extruders_cnt; i++) { + const wxString item_name = wxString::Format(_(L("Extruder %d")), i); + if (m_mode == mmMultiAsSingle) append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder); - if (i==0) // don't use M600 for default extruder, if multimaterial print is selected - continue; append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu); + [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu, + [](){return true;}, this); } - wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, _(L("Change extruder")), _(L("Use another extruder"))); + const wxString change_extruder_menu_name = m_mode == mmMultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); + + wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); change_extruder_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "change_extruder")); + ManipulationMode mode = m_mode; + Slic3r::GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, mode, change_extruder_menu_item](wxUpdateUIEvent& evt) { + enable_menu_item(evt, [this](){return m_mode == mmMultiAsSingle;}, change_extruder_menu_item, this); }, + change_extruder_menu_item->GetId()); + const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); wxMenuItem* add_color_change_menu_item = menu.AppendSubMenu(add_color_change_menu, menu_name, ""); add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m")); } } - else - append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", - [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu); append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "", - [this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu); + [this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu, + []() {return true; }, this); append_menu_item(&menu, wxID_ANY, _(L("Add custom G-code")), "", - [this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu); + [this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu, + []() {return true; }, this); Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); @@ -3499,7 +3607,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) else if (m_show_edit_menu) { wxMenu menu; - std::set::iterator it = m_ticks_.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); + std::set::iterator it = m_ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); const bool is_color_change = it->gcode == Slic3r::ColorChangeCode; append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) : @@ -3571,17 +3679,17 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick - auto it = m_ticks_.find(TICK_CODE{ tick }); - if (it == m_ticks_.end()) + auto it = m_ticks.find(TICK_CODE{ tick }); + if (it == m_ticks.end()) { std::string color = ""; if (code == Slic3r::ColorChangeCode) { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - if (m_state == msSingleExtruder && !m_ticks_.empty()) { - auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), TICK_CODE{ tick }); - while (before_tick_it != m_ticks_.begin()) { + if (m_mode == mmSingleExtruder && !m_ticks.empty()) { + auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick }); + while (before_tick_it != m_ticks.begin()) { --before_tick_it; if (before_tick_it->gcode == Slic3r::ColorChangeCode) { color = before_tick_it->color; @@ -3618,14 +3726,14 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) } int extruder = 1; - if (m_state == msMultiExtruder) { + if (m_mode != mmSingleExtruder) { if (code == Slic3r::ColorChangeCode && selected_extruder >= 0) extruder = selected_extruder; else extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); } - m_ticks_.emplace(TICK_CODE{tick, code, extruder, color}); + m_ticks.emplace(TICK_CODE{tick, code, extruder, color}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3637,8 +3745,8 @@ void DoubleSlider::edit_tick() { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z exists tick - std::set::iterator it = m_ticks_.find(TICK_CODE{ tick }); - if (it != m_ticks_.end()) + std::set::iterator it = m_ticks.find(TICK_CODE{ tick }); + if (it != m_ticks.end()) { std::string edited_value; if (it->gcode == Slic3r::ColorChangeCode) @@ -3663,8 +3771,8 @@ void DoubleSlider::edit_tick() changed_tick.gcode = edited_value; } - m_ticks_.erase(it); - m_ticks_.emplace(changed_tick); + m_ticks.erase(it); + m_ticks.emplace(changed_tick); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } @@ -3677,9 +3785,9 @@ void DoubleSlider::change_extruder(int extruder) std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); // if on this Y doesn't exist tick - if (m_ticks_.find(TICK_CODE{tick}) == m_ticks_.end()) + if (m_ticks.find(TICK_CODE{tick}) == m_ticks.end()) { - m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); + m_ticks.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3699,10 +3807,10 @@ void DoubleSlider::edit_extruder_sequence() m_extruders_sequence = from_dlg_val; - auto it = m_ticks_.begin(); - while (it != m_ticks_.end()) { + auto it = m_ticks.begin(); + while (it != m_ticks.end()) { if (it->gcode == Slic3r::ExtruderChangeCode) - it = m_ticks_.erase(it); + it = m_ticks.erase(it); else ++it; } @@ -3717,7 +3825,7 @@ void DoubleSlider::edit_extruder_sequence() while (tick <= m_max_value) { int cur_extruder = m_extruders_sequence.extruders[extruder]; - m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]}); + m_ticks.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]}); extruder++; if (extruder == extr_cnt) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 31e60d7d6..87cc922cf 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -821,20 +821,15 @@ public: EnableTickManipulation(false); } - enum ManipulationState { - msSingleExtruder, // single extruder printer preset is selected - msMultiAsSingle, // multiple extruder printer preset is selected, but + enum ManipulationMode { + mmSingleExtruder, // single extruder printer preset is selected + mmMultiAsSingle, // multiple extruder printer preset is selected, but // this mode works just for Single extruder print // (For all print from objects settings is used just one extruder) - msMultiExtruder // multiple extruder printer preset is selected + mmMultiExtruder // multiple extruder printer preset is selected }; - void SetManipulationState(ManipulationState state) { - m_state = state; - } - void SetManipulationState(int extruders_cnt) { - m_state = extruders_cnt ==1 ? msSingleExtruder : msMultiExtruder; - } - ManipulationState GetManipulationState() const { return m_state; } + void SetManipulationMode(ManipulationMode mode) { m_mode = mode; } + ManipulationMode GetManipulationMode() const { return m_mode; } bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } bool is_one_layer() const { return m_is_one_layer; } @@ -860,6 +855,17 @@ public: void change_extruder(int extruder); void edit_extruder_sequence(); + struct TICK_CODE + { + bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; } + bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; } + + int tick = 0; + std::string gcode = Slic3r::ColorChangeCode; + int extruder = 0; + std::string color; + }; + protected: void render(); @@ -881,7 +887,6 @@ protected: void detect_selected_slider(const wxPoint& pt); void correct_lower_value(); void correct_higher_value(); - wxString get_tooltip(IconFocus icon_focus); void move_current_thumb(const bool condition); void action_tick(const TicksAction action); void enter_window(wxMouseEvent& event, const bool enter); @@ -897,6 +902,10 @@ protected: wxSize get_size(); void get_size(int *w, int *h); double get_double_value(const SelectedSlider& selection); + wxString get_tooltip(IconFocus icon_focus); + bool get_color_for_tick( wxColour& color, + std::set::const_iterator tick_it, + const std::vector& colors) const; private: bool is_osx { false }; @@ -929,7 +938,7 @@ private: bool m_show_edit_menu = false; bool m_edit_extruder_sequence = false; bool m_suppress_add_code = false; - ManipulationState m_state = msSingleExtruder; + ManipulationMode m_mode = mmSingleExtruder; std::string m_custom_gcode = ""; std::string m_pause_print_msg; @@ -960,21 +969,8 @@ private: std::vector m_line_pens; std::vector m_segm_pens; - std::set m_ticks; std::vector m_values; - - struct TICK_CODE - { - bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; } - bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; } - - int tick = 0; - std::string gcode = Slic3r::ColorChangeCode; - int extruder = 0; - std::string color; - }; - - std::set m_ticks_; + std::set m_ticks; public: struct ExtrudersSequence From c0b90f68ab54bb327227ad0e0aed947ca46c8837 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 9 Jan 2020 17:12:40 +0100 Subject: [PATCH 27/85] force creating static library for libnest2d --- src/libnest2d/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt index 6484da3d0..592ab069c 100644 --- a/src/libnest2d/CMakeLists.txt +++ b/src/libnest2d/CMakeLists.txt @@ -24,7 +24,7 @@ set(LIBNEST2D_SRCFILES src/libnest2d.cpp ) -add_library(libnest2d ${LIBNEST2D_SRCFILES}) +add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES}) target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost) From cc2b9b88495532415e9a688d3fe85839944b6bc4 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 9 Jan 2020 10:32:52 +0100 Subject: [PATCH 28/85] ToolOrdering: Removed unused parameter. --- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- src/libslic3r/GCode/ToolOrdering.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 123656e43..15d7d368f 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -111,7 +111,7 @@ void ToolOrdering::initialize_layers(std::vector &zs) coordf_t zmax = zs[i] + EPSILON; for (; j < zs.size() && zs[j] <= zmax; ++ j) ; // Assign an average print_z to the set of layers with nearly equal print_z. - m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr)); + m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]))); i = j; } } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index dcb93c021..0597fcf7f 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -73,7 +73,7 @@ private: class LayerTools { public: - LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) : + LayerTools(const coordf_t z) : print_z(z), has_object(false), has_support(false), From 15eedef74b5cd57f9a4189e5da54eac35336993c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 10 Jan 2020 11:26:52 +0100 Subject: [PATCH 29/85] Refactoring of ToolOrdering (wipe into infill / object) Refactoring of GCode::_do_export() Helper lower_bound and search functions similar to std, but without needing the value object explicitely. --- src/libslic3r/GCode.cpp | 597 ++++++++++++++------------- src/libslic3r/GCode.hpp | 4 +- src/libslic3r/GCode/ToolOrdering.cpp | 73 ++-- src/libslic3r/GCode/ToolOrdering.hpp | 9 +- src/libslic3r/Print.hpp | 20 +- src/libslic3r/libslic3r.h | 47 +++ 6 files changed, 428 insertions(+), 322 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index abfa87a75..c43d35fb4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -792,6 +792,297 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str()); } +// free functions called by GCode::_do_export() +namespace DoExport { + static void init_time_estimators(const PrintConfig &config, GCodeTimeEstimator &normal_time_estimator, GCodeTimeEstimator &silent_time_estimator, bool &silent_time_estimator_enabled) + { + // resets time estimators + normal_time_estimator.reset(); + normal_time_estimator.set_dialect(config.gcode_flavor); + normal_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]); + silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode; + + // Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values + // and let the user to enter the G-code limits into the start G-code. + // If the following block is enabled for other firmwares than the Marlin, then the function + // this->print_machine_envelope(file, print); + // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor. + if (config.gcode_flavor.value == gcfMarlin) { + normal_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values[0]); + normal_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values[0]); + normal_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values[0]); + normal_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values[0]); + normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values[0]); + normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values[0]); + normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values[0]); + normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values[0]); + normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values[0]); + normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values[0]); + normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values[0]); + normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values[0]); + normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values[0]); + normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values[0]); + normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values[0]); + normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values[0]); + + if (silent_time_estimator_enabled) + { + silent_time_estimator.reset(); + silent_time_estimator.set_dialect(config.gcode_flavor); + silent_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]); + /* "Stealth mode" values can be just a copy of "normal mode" values + * (when they aren't input for a printer preset). + * Thus, use back value from values, instead of second one, which could be absent + */ + silent_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values.back()); + silent_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values.back()); + silent_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values.back()); + silent_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values.back()); + silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values.back()); + silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values.back()); + silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values.back()); + silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values.back()); + silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values.back()); + silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values.back()); + silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values.back()); + silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values.back()); + silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values.back()); + silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values.back()); + silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values.back()); + silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values.back()); + if (config.single_extruder_multi_material) { + // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they + // are considered to be active for the single extruder multi-material printers only. + silent_time_estimator.set_filament_load_times(config.filament_load_time.values); + silent_time_estimator.set_filament_unload_times(config.filament_unload_time.values); + } + } + } + // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful. + if (config.single_extruder_multi_material) { + // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they + // are considered to be active for the single extruder multi-material printers only. + normal_time_estimator.set_filament_load_times(config.filament_load_time.values); + normal_time_estimator.set_filament_unload_times(config.filament_unload_time.values); + } + } + + static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer) + { + // resets analyzer + analyzer.reset(); + + // send extruder offset data to analyzer + GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets; + unsigned int num_extruders = static_cast(config.nozzle_diameter.values.size()); + for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) + { + Vec2d offset = config.extruder_offset.get_at(extruder_id); + if (!offset.isApprox(Vec2d::Zero())) + extruder_offsets[extruder_id] = offset; + } + analyzer.set_extruder_offsets(extruder_offsets); + + // tell analyzer about the extrusion axis + analyzer.set_extrusion_axis(config.get_extrusion_axis()[0]); + + // send extruders count to analyzer to allow it to detect invalid extruder idxs + analyzer.set_extruders_count(num_extruders); + + // tell analyzer about the gcode flavor + analyzer.set_gcode_flavor(config.gcode_flavor); + } + + static double autospeed_volumetric_limit(const Print &print) + { + // get the minimum cross-section used in the print + std::vector mm3_per_mm; + for (auto object : print.objects()) { + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { + const PrintRegion* region = print.regions()[region_id]; + for (auto layer : object->layers()) { + const LayerRegion* layerm = layer->regions()[region_id]; + if (region->config().get_abs_value("perimeter_speed") == 0 || + region->config().get_abs_value("small_perimeter_speed") == 0 || + region->config().get_abs_value("external_perimeter_speed") == 0 || + region->config().get_abs_value("bridge_speed") == 0) + mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm()); + if (region->config().get_abs_value("infill_speed") == 0 || + region->config().get_abs_value("solid_infill_speed") == 0 || + region->config().get_abs_value("top_solid_infill_speed") == 0 || + region->config().get_abs_value("bridge_speed") == 0) + mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm()); + } + } + if (object->config().get_abs_value("support_material_speed") == 0 || + object->config().get_abs_value("support_material_interface_speed") == 0) + for (auto layer : object->support_layers()) + mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm()); + } + // filter out 0-width segments + mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end()); + double volumetric_speed = 0.; + if (! mm3_per_mm.empty()) { + // In order to honor max_print_speed we need to find a target volumetric + // speed that we can use throughout the print. So we define this target + // volumetric speed as the volumetric speed produced by printing the + // smallest cross-section at the maximum speed: any larger cross-section + // will need slower feedrates. + volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value; + // limit such volumetric speed with max_volumetric_speed if set + if (print.config().max_volumetric_speed.value > 0) + volumetric_speed = std::min(volumetric_speed, print.config().max_volumetric_speed.value); + } + return volumetric_speed; + } + + static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention) + { + // Calculate wiping points if needed + if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) { + Points skirt_points; + for (const ExtrusionEntity *ee : print.skirt().entities) + for (const ExtrusionPath &path : dynamic_cast(ee)->paths) + append(skirt_points, path.polyline.points); + if (! skirt_points.empty()) { + Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); + Polygons skirts; + for (unsigned int extruder_id : print.extruders()) { + const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id); + Polygon s(outer_skirt); + s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1))); + skirts.emplace_back(std::move(s)); + } + ooze_prevention.enable = true; + ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.)); + #if 0 + require "Slic3r/SVG.pm"; + Slic3r::SVG::output( + "ooze_prevention.svg", + red_polygons => \@skirts, + polygons => [$outer_skirt], + points => $gcodegen->ooze_prevention->standby_points, + ); + #endif + } + } + } + + #if ENABLE_THUMBNAIL_GENERATOR + template + static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector &sizes, WriteToOutput &output, ThrowIfCanceledCallback throw_if_canceled) + { + // Write thumbnails using base64 encoding + if (thumbnail_cb != nullptr) + { + const size_t max_row_length = 78; + ThumbnailsList thumbnails; + thumbnail_cb(thumbnails, sizes, true, true, true, true); + for (const ThumbnailData& data : thumbnails) + { + if (data.is_valid()) + { + size_t png_size = 0; + void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); + if (png_data != nullptr) + { + std::string encoded; + encoded.resize(boost::beast::detail::base64::encoded_size(png_size)); + encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size)); + + output((boost::format("\n;\n; thumbnail begin %dx%d %d\n") % data.width % data.height % encoded.size()).str().c_str()); + + unsigned int row_count = 0; + while (encoded.size() > max_row_length) + { + output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str()); + encoded = encoded.substr(max_row_length); + ++row_count; + } + + if (encoded.size() > 0) + output((boost::format("; %s\n") % encoded).str().c_str()); + + output("; thumbnail end\n;\n"); + + mz_free(png_data); + } + } + throw_if_canceled(); + } + } + } + #endif // ENABLE_THUMBNAIL_GENERATOR + + // Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section. + static std::string update_print_stats_and_format_filament_stats( + const GCodeTimeEstimator &normal_time_estimator, + const GCodeTimeEstimator &silent_time_estimator, + const bool silent_time_estimator_enabled, + const bool has_wipe_tower, + const WipeTowerData &wipe_tower_data, + const std::vector &extruders, + PrintStatistics &print_statistics) + { + std::string filament_stats_string_out; + + print_statistics.clear(); + print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhms(); + print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhms() : "N/A"; + print_statistics.estimated_normal_color_print_times = normal_time_estimator.get_color_times_dhms(true); + if (silent_time_estimator_enabled) + print_statistics.estimated_silent_color_print_times = silent_time_estimator.get_color_times_dhms(true); + print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges); + if (! extruders.empty()) { + std::pair out_filament_used_mm ("; filament used [mm] = ", 0); + std::pair out_filament_used_cm3("; filament used [cm3] = ", 0); + std::pair out_filament_used_g ("; filament used [g] = ", 0); + std::pair out_filament_cost ("; filament cost = ", 0); + for (const Extruder &extruder : extruders) { + double used_filament = extruder.used_filament() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] : 0.f); + double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter + double filament_weight = extruded_volume * extruder.filament_density() * 0.001; + double filament_cost = filament_weight * extruder.filament_cost() * 0.001; + auto append = [&extruder, &extruders](std::pair &dst, const char *tmpl, double value) { + while (dst.second < extruder.id()) { + // Fill in the non-printing extruders with zeros. + dst.first += (dst.second > 0) ? ", 0" : "0"; + ++ dst.second; + } + if (dst.second > 0) + dst.first += ", "; + char buf[64]; + sprintf(buf, tmpl, value); + dst.first += buf; + ++ dst.second; + }; + print_statistics.filament_stats.insert(std::pair{extruder.id(), (float)used_filament}); + append(out_filament_used_mm, "%.1lf", used_filament); + append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001); + if (filament_weight > 0.) { + print_statistics.total_weight = print_statistics.total_weight + filament_weight; + append(out_filament_used_g, "%.1lf", filament_weight); + if (filament_cost > 0.) { + print_statistics.total_cost = print_statistics.total_cost + filament_cost; + append(out_filament_cost, "%.1lf", filament_cost); + } + } + print_statistics.total_used_filament += used_filament; + print_statistics.total_extruded_volume += extruded_volume; + print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.; + print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.; + } + filament_stats_string_out += out_filament_used_mm.first; + filament_stats_string_out += out_filament_used_cm3.first; + if (out_filament_used_g.second) + filament_stats_string_out += out_filament_used_g.first; + if (out_filament_cost.second) + filament_stats_string_out += out_filament_cost.first; + } + return filament_stats_string_out; + } +} + #if ENABLE_THUMBNAIL_GENERATOR void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb) #else @@ -800,99 +1091,10 @@ void GCode::_do_export(Print& print, FILE* file) { PROFILE_FUNC(); - // resets time estimators - m_normal_time_estimator.reset(); - m_normal_time_estimator.set_dialect(print.config().gcode_flavor); - m_normal_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]); - m_silent_time_estimator_enabled = (print.config().gcode_flavor == gcfMarlin) && print.config().silent_mode; - - // Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values - // and let the user to enter the G-code limits into the start G-code. - // If the following block is enabled for other firmwares than the Marlin, then the function - // this->print_machine_envelope(file, print); - // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor. - if (print.config().gcode_flavor.value == gcfMarlin) { - m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]); - m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]); - m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]); - m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]); - - if (m_silent_time_estimator_enabled) - { - m_silent_time_estimator.reset(); - m_silent_time_estimator.set_dialect(print.config().gcode_flavor); - m_silent_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]); - /* "Stealth mode" values can be just a copy of "normal mode" values - * (when they aren't input for a printer preset). - * Thus, use back value from values, instead of second one, which could be absent - */ - m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back()); - m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back()); - m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back()); - m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back()); - if (print.config().single_extruder_multi_material) { - // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they - // are considered to be active for the single extruder multi-material printers only. - m_silent_time_estimator.set_filament_load_times(print.config().filament_load_time.values); - m_silent_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values); - } - } - } - // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful. - if (print.config().single_extruder_multi_material) { - // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they - // are considered to be active for the single extruder multi-material printers only. - m_normal_time_estimator.set_filament_load_times(print.config().filament_load_time.values); - m_normal_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values); - } - - // resets analyzer - m_analyzer.reset(); - - // send extruder offset data to analyzer - GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets; - for (unsigned int extruder_id : print.extruders()) - { - Vec2d offset = print.config().extruder_offset.get_at(extruder_id); - if (!offset.isApprox(Vec2d::Zero())) - extruder_offsets[extruder_id] = offset; - } - m_analyzer.set_extruder_offsets(extruder_offsets); - - // tell analyzer about the extrusion axis - m_analyzer.set_extrusion_axis(print.config().get_extrusion_axis()[0]); - - // send extruders count to analyzer to allow it to detect invalid extruder idxs - const ConfigOptionStrings* extruders_opt = dynamic_cast(print.config().option("extruder_colour")); - const ConfigOptionStrings* filamemts_opt = dynamic_cast(print.config().option("filament_colour")); - m_analyzer.set_extruders_count(std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size())); - - // tell analyzer about the gcode flavor - m_analyzer.set_gcode_flavor(print.config().gcode_flavor); + DoExport::init_time_estimators(print.config(), + // modifies the following: + m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled); + DoExport::init_gcode_analyzer(print.config(), m_analyzer); // resets analyzer's tracking data m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; @@ -914,8 +1116,7 @@ void GCode::_do_export(Print& print, FILE* file) std::sort(zs.begin(), zs.end()); m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); } - } - else { + } else { // Print all objects with the same print_z together. std::vector zs; for (auto object : print.objects()) { @@ -938,47 +1139,7 @@ void GCode::_do_export(Print& print, FILE* file) Model* model = print.get_object(0)->model_object()->get_model(); m_custom_gcode_per_print_z = model->custom_gcode_per_print_z; - // Initialize autospeed. - { - // get the minimum cross-section used in the print - std::vector mm3_per_mm; - for (auto object : print.objects()) { - for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) { - const PrintRegion* region = print.regions()[region_id]; - for (auto layer : object->layers()) { - const LayerRegion* layerm = layer->regions()[region_id]; - if (region->config().get_abs_value("perimeter_speed") == 0 || - region->config().get_abs_value("small_perimeter_speed") == 0 || - region->config().get_abs_value("external_perimeter_speed") == 0 || - region->config().get_abs_value("bridge_speed") == 0) - mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm()); - if (region->config().get_abs_value("infill_speed") == 0 || - region->config().get_abs_value("solid_infill_speed") == 0 || - region->config().get_abs_value("top_solid_infill_speed") == 0 || - region->config().get_abs_value("bridge_speed") == 0) - mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm()); - } - } - if (object->config().get_abs_value("support_material_speed") == 0 || - object->config().get_abs_value("support_material_interface_speed") == 0) - for (auto layer : object->support_layers()) - mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm()); - } - print.throw_if_canceled(); - // filter out 0-width segments - mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end()); - if (!mm3_per_mm.empty()) { - // In order to honor max_print_speed we need to find a target volumetric - // speed that we can use throughout the print. So we define this target - // volumetric speed as the volumetric speed produced by printing the - // smallest cross-section at the maximum speed: any larger cross-section - // will need slower feedrates. - m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value; - // limit such volumetric speed with max_volumetric_speed if set - if (print.config().max_volumetric_speed.value > 0) - m_volumetric_speed = std::min(m_volumetric_speed, print.config().max_volumetric_speed.value); - } - } + m_volumetric_speed = DoExport::autospeed_volumetric_limit(print); print.throw_if_canceled(); m_cooling_buffer = make_unique(*this); @@ -996,47 +1157,9 @@ void GCode::_do_export(Print& print, FILE* file) // Write information on the generator. _write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str()); -#if ENABLE_THUMBNAIL_GENERATOR - // Write thumbnails using base64 encoding - if (thumbnail_cb != nullptr) - { - const size_t max_row_length = 78; - ThumbnailsList thumbnails; - thumbnail_cb(thumbnails, print.full_print_config().option("thumbnails")->values, true, true, true, true); - for (const ThumbnailData& data : thumbnails) - { - if (data.is_valid()) - { - size_t png_size = 0; - void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); - if (png_data != nullptr) - { - std::string encoded; - encoded.resize(boost::beast::detail::base64::encoded_size(png_size)); - encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size)); - - _write_format(file, "\n;\n; thumbnail begin %dx%d %d\n", data.width, data.height, encoded.size()); - - unsigned int row_count = 0; - while (encoded.size() > max_row_length) - { - _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str()); - encoded = encoded.substr(max_row_length); - ++row_count; - } - - if (encoded.size() > 0) - _write_format(file, "; %s\n", encoded.c_str()); - - _write(file, "; thumbnail end\n;\n"); - - mz_free(png_data); - } - } - print.throw_if_canceled(); - } - } -#endif // ENABLE_THUMBNAIL_GENERATOR + DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option("thumbnails")->values, + [this, file](const char* sz) { this->_write(file, sz); }, + [&print]() { print.throw_if_canceled(); }); // Write notes (content of the Print Settings tab -> Notes) { @@ -1079,9 +1202,6 @@ void GCode::_do_export(Print& print, FILE* file) _writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag); } - // Hold total number of print toolchanges. Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). - int total_toolchanges = std::max(0, print.wipe_tower_data().number_of_toolchanges); - // Prepare the helper object for replacing placeholders in custom G-code and output filename. m_placeholder_parser = print.placeholder_parser(); m_placeholder_parser.update_timestamp(); @@ -1187,7 +1307,8 @@ void GCode::_do_export(Print& print, FILE* file) // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); - m_placeholder_parser.set("total_toolchanges", total_toolchanges); + m_placeholder_parser.set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). + std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id); // Set bed temperature if the start G-code does not contain any bed temp control G-codes. this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); @@ -1195,12 +1316,8 @@ void GCode::_do_export(Print& print, FILE* file) this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); if (m_enable_analyzer) - { // adds tag for analyzer - char buf[32]; - sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); - _writeln(file, buf); - } + _write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); // Write the custom start G-code _writeln(file, start_gcode); @@ -1228,35 +1345,8 @@ void GCode::_do_export(Print& print, FILE* file) } // Calculate wiping points if needed - if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) { - Points skirt_points; - for (const ExtrusionEntity *ee : print.skirt().entities) - for (const ExtrusionPath &path : dynamic_cast(ee)->paths) - append(skirt_points, path.polyline.points); - if (! skirt_points.empty()) { - Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); - Polygons skirts; - for (unsigned int extruder_id : print.extruders()) { - const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id); - Polygon s(outer_skirt); - s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1))); - skirts.emplace_back(std::move(s)); - } - m_ooze_prevention.enable = true; - m_ooze_prevention.standby_points = - offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.)); -#if 0 - require "Slic3r/SVG.pm"; - Slic3r::SVG::output( - "ooze_prevention.svg", - red_polygons => \@skirts, - polygons => [$outer_skirt], - points => $gcodegen->ooze_prevention->standby_points, - ); -#endif - } - print.throw_if_canceled(); - } + DoExport::init_ooze_prevention(print, m_ooze_prevention); + print.throw_if_canceled(); if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) { // Set initial extruder only after custom start G-code. @@ -1387,12 +1477,8 @@ void GCode::_do_export(Print& print, FILE* file) _write(file, m_writer.set_fan(false)); if (m_enable_analyzer) - { // adds tag for analyzer - char buf[32]; - sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); - _writeln(file, buf); - } + _write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); // Process filament-specific gcode in extruder order. { @@ -1432,60 +1518,13 @@ void GCode::_do_export(Print& print, FILE* file) m_silent_time_estimator.calculate_time(false); // Get filament stats. - print.m_print_statistics.clear(); - print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); - print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A"; - print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true); - if (m_silent_time_estimator_enabled) - print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true); - print.m_print_statistics.total_toolchanges = total_toolchanges; - std::vector extruders = m_writer.extruders(); - if (! extruders.empty()) { - std::pair out_filament_used_mm ("; filament used [mm] = ", 0); - std::pair out_filament_used_cm3("; filament used [cm3] = ", 0); - std::pair out_filament_used_g ("; filament used [g] = ", 0); - std::pair out_filament_cost ("; filament cost = ", 0); - for (const Extruder &extruder : extruders) { - double used_filament = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f); - double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter - double filament_weight = extruded_volume * extruder.filament_density() * 0.001; - double filament_cost = filament_weight * extruder.filament_cost() * 0.001; - auto append = [&extruder, &extruders](std::pair &dst, const char *tmpl, double value) { - while (dst.second < extruder.id()) { - // Fill in the non-printing extruders with zeros. - dst.first += (dst.second > 0) ? ", 0" : "0"; - ++ dst.second; - } - if (dst.second > 0) - dst.first += ", "; - char buf[64]; - sprintf(buf, tmpl, value); - dst.first += buf; - ++ dst.second; - }; - print.m_print_statistics.filament_stats.insert(std::pair{extruder.id(), (float)used_filament}); - append(out_filament_used_mm, "%.1lf", used_filament); - append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001); - if (filament_weight > 0.) { - print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight; - append(out_filament_used_g, "%.1lf", filament_weight); - if (filament_cost > 0.) { - print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost; - append(out_filament_cost, "%.1lf", filament_cost); - } - } - print.m_print_statistics.total_used_filament += used_filament; - print.m_print_statistics.total_extruded_volume += extruded_volume; - print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.; - print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.; - } - _writeln(file, out_filament_used_mm.first); - _writeln(file, out_filament_used_cm3.first); - if (out_filament_used_g.second) - _writeln(file, out_filament_used_g.first); - if (out_filament_cost.second) - _writeln(file, out_filament_cost.first); - } + _write(file, DoExport::update_print_stats_and_format_filament_stats( + // Const inputs + m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled, + has_wipe_tower, print.wipe_tower_data(), + m_writer.extruders(), + // Modifies + print.m_print_statistics)); _write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight); _write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost); if (print.m_print_statistics.total_toolchanges > 0) @@ -2015,7 +2054,7 @@ void GCode::process_layer( slices_test_order.reserve(n_slices); for (size_t i = 0; i < n_slices; ++ i) slices_test_order.emplace_back(i); - std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](int i, int j) { + std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](size_t i, size_t j) { const Vec2d s1 = layer_surface_bboxes[i].size().cast(); const Vec2d s2 = layer_surface_bboxes[j].size().cast(); return s1.x() * s1.y() < s2.x() * s2.y(); @@ -2188,7 +2227,7 @@ void GCode::process_layer( m_layer = layers[instance_to_print.layer_id].layer(); } for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) { - const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, instance_to_print.instance_id, extruder_id, print_wipe_extrusions) : island.by_region; + const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region; //FIXME the following code prints regions in the order they are defined, the path is not optimized in any way. if (print.config().infill_first) { gcode += this->extrude_infill(print, by_region_specific); @@ -3277,7 +3316,7 @@ Point GCode::gcode_to_point(const Vec2d &point) const // Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed // during infill/perimeter wiping, or normally (depends on wiping_entities parameter) // Fills in by_region_per_copy_cache and returns its reference. -const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities) const +const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities) const { bool has_overrides = false; for (const auto& reg : by_region) @@ -3313,7 +3352,7 @@ const std::vector& GCode::ObjectByExtru for (unsigned int i = 0; i < overrides.size(); ++ i) { const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; // This copy (aka object instance) should be printed with this extruder, which overrides the default one. - if (this_override != nullptr && (*this_override)[copy] == extruder) + if (this_override != nullptr && (*this_override)[copy] == int(extruder)) target_eec.emplace_back(entities[i]); } } else { @@ -3322,7 +3361,7 @@ const std::vector& GCode::ObjectByExtru for (; i < overrides.size(); ++ i) { const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; // This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one. - if (this_override == nullptr || (*this_override)[copy] == -extruder-1) + if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1) target_eec.emplace_back(entities[i]); } for (; i < overrides.size(); ++ i) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index e8bc88a29..d5213d00b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -197,7 +197,7 @@ public: // append full config to the given string static void append_full_config(const Print& print, std::string& str); -protected: +private: #if ENABLE_THUMBNAIL_GENERATOR void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb); #else @@ -274,7 +274,7 @@ protected: std::vector by_region; // all extrusions for this island, grouped by regions // Fills in by_region_per_copy_cache and returns its reference. - const std::vector& by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities = false) const; + const std::vector& by_region_per_copy(std::vector &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities = false) const; }; std::vector islands; }; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 15d7d368f..8aed420cb 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -13,6 +13,8 @@ #include #include +#include + namespace Slic3r { @@ -150,14 +152,14 @@ void ToolOrdering::collect_extruders(const PrintObject &object) if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors) something_nonoverriddable = false; for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities - if (!layer_tools.wiping_extrusions().is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { + if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { something_nonoverriddable = true; break; } } if (something_nonoverriddable) - layer_tools.extruders.push_back(region.config().perimeter_extruder.value); + layer_tools.extruders.push_back(region.config().perimeter_extruder.value); layer_tools.has_object = true; } @@ -176,7 +178,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) has_infill = true; if (m_print_config_ptr) { - if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable(*fill, *m_print_config_ptr, object, region)) + if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region)) something_nonoverriddable = true; } } @@ -463,7 +465,6 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con return true; } - // Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange // and returns volume that is left to be wiped on the wipe tower. float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe) @@ -471,7 +472,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int const LayerTools& lt = *m_layer_tools; const float min_infill_volume = 0.f; // ignore infill with smaller volume than this - if (print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) + assert(volume_to_wipe >= 0.); + if (! this->something_overridable || volume_to_wipe == 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: @@ -495,13 +497,13 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int const PrintObject* object = object_list[i]; // Finds this layer: - auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers().end()) - continue; - const Layer* this_layer = *this_layer_it; + const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON); + if (this_layer == nullptr) + continue; size_t num_of_copies = object->copies().size(); - for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves + // iterate through copies (aka PrintObject instances) first, so that we mark neighbouring infills to minimize travel moves + for (unsigned int copy = 0; copy < num_of_copies; ++copy) { for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { const auto& region = *object->print()->regions()[region_id]; @@ -509,18 +511,15 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if (!region.config().wipe_into_infill && !object->config().wipe_into_objects) continue; - - if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) { + bool wipe_into_infill_only = ! object->config().wipe_into_objects && region.config().wipe_into_infill; + if (print.config().infill_first != perimeters_done || wipe_into_infill_only) { for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); if (!is_overriddable(*fill, print.config(), *object, region)) continue; - if (volume_to_wipe<=0) - continue; - - if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill) + if (wipe_into_infill_only && ! print.config().infill_first) // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder)) @@ -528,32 +527,32 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder set_extruder_override(fill, copy, new_extruder, num_of_copies); - volume_to_wipe -= float(fill->total_volume()); + if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f) + // More material was purged already than asked for. + return 0.f; } } } // Now the same for perimeters - see comments above for explanation: - if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done)) + if (object->config().wipe_into_objects && print.config().infill_first == perimeters_done) { for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { auto* fill = dynamic_cast(ee); - if (!is_overriddable(*fill, print.config(), *object, region)) - continue; - - if (volume_to_wipe<=0) - continue; - - if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { + if (is_overriddable(*fill, print.config(), *object, region) && !is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { set_extruder_override(fill, copy, new_extruder, num_of_copies); - volume_to_wipe -= float(fill->total_volume()); + if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f) + // More material was purged already than asked for. + return 0.f; } } } } } } - return std::max(0.f, volume_to_wipe); + // Some purge remains to be done on the Wipe Tower. + assert(volume_to_wipe > 0.); + return volume_to_wipe; } @@ -564,16 +563,18 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int // them again and make sure we override it. void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) { + if (! this->something_overridable) + return; + const LayerTools& lt = *m_layer_tools; unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config()); unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config()); for (const PrintObject* object : print.objects()) { // Finds this layer: - auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers().end()) - continue; - const Layer* this_layer = *this_layer_it; + const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON); + if (this_layer == nullptr) + continue; size_t num_of_copies = object->copies().size(); for (size_t copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves @@ -597,8 +598,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) if (print.config().infill_first || object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely || lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints - || std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME) - ) + || ! lt.has_extruder(region.config().infill_extruder - 1))) // we have to force override - this could violate infill_first (FIXME) set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); else { // In this case we can (and should) leave it to be printed normally. @@ -609,11 +609,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) // Now the same for perimeters - see comments above for explanation: for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { // iterate through all perimeter Collections auto* fill = dynamic_cast(ee); - if (!is_overriddable(*fill, print.config(), *object, region) - || is_entity_overridden(fill, copy) ) - continue; - - set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies); + if (is_overriddable(*fill, print.config(), *object, region) && ! is_entity_overridden(fill, copy)) + set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies); } } } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 0597fcf7f..ed7aaab43 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -48,6 +48,11 @@ public: void ensure_perimeters_infills_order(const Print& print); bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const; + bool is_overriddable_and_mark(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) { + bool out = this->is_overriddable(ee, print_config, object, region); + this->something_overridable |= out; + return out; + } void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; } @@ -60,10 +65,12 @@ private: // Returns true in case that entity is not printed with its usual extruder for a given copy: bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const { - return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1); + auto it = entity_map.find(entity); + return it == entity_map.end() ? false : it->second[copy_id] != -1; } std::map entity_map; // to keep track of who prints what + bool something_overridable = false; bool something_overridden = false; const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to }; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 95c7b656a..c434eec43 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -15,6 +15,8 @@ #include "GCode/ThumbnailData.hpp" #endif // ENABLE_THUMBNAIL_GENERATOR +#include "libslic3r.h" + namespace Slic3r { class Print; @@ -116,8 +118,21 @@ public: size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); } size_t layer_count() const { return m_layers.size(); } void clear_layers(); - Layer* get_layer(int idx) { return m_layers[idx]; } - const Layer* get_layer(int idx) const { return m_layers[idx]; } + const Layer* get_layer(int idx) const { return m_layers[idx]; } + Layer* get_layer(int idx) { return m_layers[idx]; } + // Get a layer exactly at print_z. + const Layer* get_layer_at_printz(coordf_t print_z) const { + auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; }); + return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it; + } + Layer* get_layer_at_printz(coordf_t print_z) { return const_cast(std::as_const(*this).get_layer_at_printz(print_z)); } + // Get a layer approximately at print_z. + const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const { + coordf_t limit = print_z + epsilon; + auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; }); + return (it == m_layers.end() || (*it)->print_z < print_z - epsilon) ? nullptr : *it; + } + Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); } // print_z: top of the layer; slice_z: center of the layer. Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z); @@ -345,6 +360,7 @@ public: const PrintConfig& config() const { return m_config; } const PrintObjectConfig& default_object_config() const { return m_default_object_config; } const PrintRegionConfig& default_region_config() const { return m_default_region_config; } + //FIXME returning const vector to non-const PrintObject*, caller could modify PrintObjects! const PrintObjectPtrs& objects() const { return m_objects; } PrintObject* get_object(size_t idx) { return m_objects[idx]; } const PrintObject* get_object(size_t idx) const { return m_objects[idx]; } diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index afbf94fa3..d3e4992ce 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -158,6 +158,53 @@ inline std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } +// Variant of std::lower_bound() with compare predicate, but without the key. +// This variant is very useful in case that the T type is large or it does not even have a public constructor. +template +ForwardIt lower_bound_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key) +{ + ForwardIt it; + typename std::iterator_traits::difference_type count, step; + count = std::distance(first, last); + + while (count > 0) { + it = first; + step = count / 2; + std::advance(it, step); + if (lower_thank_key(*it)) { + first = ++it; + count -= step + 1; + } + else + count = step; + } + return first; +} + +// from https://en.cppreference.com/w/cpp/algorithm/lower_bound +template> +ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={}) +{ + // Note: BOTH type T and the type after ForwardIt is dereferenced + // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. + // This is stricter than lower_bound requirement (see above) + + first = std::lower_bound(first, last, value, comp); + return first != last && !comp(value, *first) ? first : last; +} + +// from https://en.cppreference.com/w/cpp/algorithm/lower_bound +template +ForwardIt binary_find_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key, EqualToKeyPredicate equal_to_key) +{ + // Note: BOTH type T and the type after ForwardIt is dereferenced + // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. + // This is stricter than lower_bound requirement (see above) + + first = lower_bound_by_predicate(first, last, lower_thank_key); + return first != last && equal_to_key(*first) ? first : last; +} + template static inline T sqr(T x) { From 702a489b038bcde81c3eb79393586e460e8b8660 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 10 Jan 2020 11:53:39 +0100 Subject: [PATCH 30/85] Fixing compilation isue on non-MS compilers. --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c43d35fb4..7bd352537 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -970,7 +970,7 @@ namespace DoExport { #if ENABLE_THUMBNAIL_GENERATOR template - static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector &sizes, WriteToOutput &output, ThrowIfCanceledCallback throw_if_canceled) + static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector &sizes, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled) { // Write thumbnails using base64 encoding if (thumbnail_cb != nullptr) From 9038dc21e85d1aa956fcb0429659884d028dee66 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 10 Jan 2020 15:51:35 +0100 Subject: [PATCH 31/85] Fixing regression issue after G-code export refactoring. --- src/libslic3r/ExtrusionEntityCollection.cpp | 39 ++++++++++++++------- src/libslic3r/ExtrusionEntityCollection.hpp | 19 ++++++++-- src/libslic3r/GCode.cpp | 6 ++-- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index 7e0e1fc9c..147a60d95 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -6,6 +6,26 @@ namespace Slic3r { +void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role) +{ + if (role != erMixed) { + auto first = extrusion_entities.begin(); + auto last = extrusion_entities.end(); + auto result = first; + while (first != last) { + // The caller wants only paths with a specific extrusion role. + auto role2 = (*first)->role(); + if (role != role2) { + // This extrusion entity does not match the role asked. + assert(role2 != erMixed); + *result = *first; + ++ result; + } + ++ first; + } + } +} + ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths) : no_sort(false) { @@ -76,19 +96,12 @@ void ExtrusionEntityCollection::remove(size_t i) ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const ExtrusionEntitiesPtr& extrusion_entities, const Point &start_near, ExtrusionRole role) { - ExtrusionEntityCollection out; - for (const ExtrusionEntity *ee : extrusion_entities) { - if (role != erMixed) { - // The caller wants only paths with a specific extrusion role. - auto role2 = ee->role(); - if (role != role2) { - // This extrusion entity does not match the role asked. - assert(role2 != erMixed); - continue; - } - } - out.entities.emplace_back(ee->clone()); - } + // Return a filtered copy of the collection. + ExtrusionEntityCollection out; + out.entities = filter_by_extrusion_role(extrusion_entities, role); + // Clone the extrusion entities. + for (auto &ptr : out.entities) + ptr = ptr->clone(); chain_and_reorder_extrusion_entities(out.entities, &start_near); return out; } diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp index e529bea02..8aacb4d46 100644 --- a/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/src/libslic3r/ExtrusionEntityCollection.hpp @@ -6,6 +6,21 @@ namespace Slic3r { +// Remove those items from extrusion_entities, that do not match role. +// Do nothing if role is mixed. +// Removed elements are NOT being deleted. +void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role); + +// Return new vector of ExtrusionEntities* with only those items from input extrusion_entities, that match role. +// Return all extrusion entities if role is mixed. +// Returned extrusion entities are shared with the source vector, they are NOT cloned, they are considered to be owned by extrusion_entities. +inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role) +{ + ExtrusionEntitiesPtr out { extrusion_entities }; + filter_by_extrusion_role_in_place(out, role); + return out; +} + class ExtrusionEntityCollection : public ExtrusionEntity { public: @@ -67,7 +82,7 @@ public: void remove(size_t i); static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed); ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const - { return (this->no_sort || role == erMixed) ? *this : chained_path_from(this->entities, start_near, role); } + { return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); } void reverse(); const Point& first_point() const { return this->entities.front()->first_point(); } const Point& last_point() const { return this->entities.back()->last_point(); } @@ -107,6 +122,6 @@ public: } }; -} +} // namespace Slic3r #endif diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7bd352537..942558f27 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2848,9 +2848,9 @@ std::string GCode::extrude_infill(const Print &print, const std::vectorconfig()); -// for (ExtrusionEntity *fill : ExtrusionEntityCollection::chained_path_from(region.infills, m_last_pos).entities) { - // Don't sort the infills, they contain gap fill, which shall be extruded after normal fills. - for (const ExtrusionEntity *fill : region.infills) { + ExtrusionEntitiesPtr extrusions { region.infills }; + chain_and_reorder_extrusion_entities(extrusions, &m_last_pos); + for (const ExtrusionEntity *fill : extrusions) { auto *eec = dynamic_cast(fill); if (eec) { for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities) From 02b2e206281e9cfc89c7efbb4d7d294c1332fe89 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 10 Jan 2020 16:49:07 +0100 Subject: [PATCH 32/85] Context menus improvements. Disabling unused extruders for color_change --- src/slic3r/GUI/GUI_Preview.cpp | 57 +++++++++- src/slic3r/GUI/GUI_Preview.hpp | 3 +- src/slic3r/GUI/Plater.cpp | 32 ------ src/slic3r/GUI/Plater.hpp | 1 - src/slic3r/GUI/wxExtensions.cpp | 190 ++++++++++++++++++-------------- src/slic3r/GUI/wxExtensions.hpp | 18 ++- 6 files changed, 179 insertions(+), 122 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index acb5c89e3..fceaeba3b 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -692,11 +692,60 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); m_slider->EnableTickManipulation(color_print_enable); - // Detect and set manipulation mode for double slider - m_slider->SetManipulationMode( wxGetApp().extruders_edited_cnt() == 1 ? DoubleSlider::mmSingleExtruder : - wxGetApp().plater()->is_one_extruder_printed_model() ? DoubleSlider::mmMultiAsSingle : - DoubleSlider::mmMultiExtruder); + update_double_slider_mode(); +} + +void Preview::update_double_slider_mode() +{ + // true -> single-extruder printer profile OR + // multi-extruder printer profile , but whole model is printed by only one extruder + // false -> multi-extruder printer profile , and model is printed by several extruders + bool one_extruder_printed_model = true; + + // extruder used for whole model for multi-extruder printer profile + int only_extruder = -1; + + if (wxGetApp().extruders_edited_cnt() > 1) + { + const ModelObjectPtrs& objects = wxGetApp().plater()->model().objects; + + // check if whole model uses just only one extruder + if (!objects.empty()) + { + const int extruder = objects[0]->config.has("extruder") ? + objects[0]->config.option("extruder")->getInt() : 0; + + auto is_one_extruder_printed_model = [objects, extruder]() + { + for (ModelObject* object : objects) + { + if (object->config.has("extruder") && + object->config.option("extruder")->getInt() != extruder) + return false; + + if (object->volumes.size() > 1) + for (ModelVolume* volume : object->volumes) + if (volume->config.has("extruder") && + volume->config.option("extruder")->getInt() != extruder) + return false; + + for (const auto& range : object->layer_config_ranges) + if (range.second.has("extruder") && + range.second.option("extruder")->getInt() != extruder) + return false; + } + return true; + }; + + if (is_one_extruder_printed_model()) + only_extruder = extruder; + else + one_extruder_printed_model = false; + } + } + + m_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder); } void Preview::reset_double_slider() diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 92ec15b22..ae93e2ff0 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -157,8 +157,9 @@ private: void create_double_slider(); void check_slider_values(std::vector &ticks_from_model, const std::vector &layers_z); - void update_double_slider(const std::vector& layers_z, bool keep_z_range = false); void reset_double_slider(); + void update_double_slider(const std::vector& layers_z, bool keep_z_range = false); + void update_double_slider_mode(); // update DoubleSlider after keyDown in canvas void update_double_slider_from_canvas(wxKeyEvent& event); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 01241bd8f..2c0742559 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5358,38 +5358,6 @@ bool Plater::is_export_gcode_scheduled() const return p->background_process.is_export_scheduled(); } -bool Plater::is_one_extruder_printed_model() -{ - if (wxGetApp().extruders_edited_cnt() == 1) - return true; - - // check if model use just one extruder - const ModelObjectPtrs& objects = p->model.objects; - if (!objects.empty()) - { - const size_t extruder = objects[0]->config.has("extruder") ? - objects[0]->config.option("extruder")->getInt() : 0; - for (ModelObject* object : objects) - { - if (object->config.has("extruder") && - object->config.option("extruder")->getInt() != extruder) - return false; - - for (ModelVolume* volume : object->volumes) - if (volume->config.has("extruder") && - volume->config.option("extruder")->getInt() != extruder) - return false; - - for (const auto& range : object->layer_config_ranges) - if (range.second.has("extruder") && - range.second.option("extruder")->getInt() != extruder) - return false; - } - } - - return true; -} - int Plater::get_selected_object_idx() { return p->get_selected_object_idx(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 2c7e13e45..479397705 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -234,7 +234,6 @@ public: void set_project_filename(const wxString& filename); bool is_export_gcode_scheduled() const; - bool is_one_extruder_printed_model(); int get_selected_object_idx(); bool is_single_full_object_selection() const; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8ccf605f5..a831f32bb 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2883,7 +2883,9 @@ bool DoubleSlider::get_color_for_tick(wxColour& color, std::set::cons return std::min(extruders_cnt - 1, std::max(current_extruder - 1, 0)); }; - auto get_color_idx_for_color_change = [get_m600_color_idx](const std::set& ticks, std::set::const_iterator it) + const int extruder = std::max(1, m_only_extruder); + + auto get_color_idx_for_color_change = [get_m600_color_idx, extruder](const std::set& ticks, std::set::const_iterator it) { auto it_n = it; bool is_tool_change = false; @@ -2896,7 +2898,7 @@ bool DoubleSlider::get_color_for_tick(wxColour& color, std::set::cons break; } } - if (!is_tool_change && it->extruder == 0) // use correct extruder number instead of 0 + if (!is_tool_change && it->extruder == extruder) // use correct extruder number instead of 0 return get_m600_color_idx(ticks, it); return -1; @@ -2943,9 +2945,9 @@ void DoubleSlider::draw_colored_band(wxDC& dc) const std::vector& colors = Slic3r::GUI::wxGetApp().plater()->get_colors_for_color_print(); - const wxColour bg_clr = GetParent()->GetBackgroundColour(); - - wxColour clr = m_ticks.empty() || m_mode == mmMultiExtruder ? bg_clr : wxColour(colors[0]); + wxColour clr = m_ticks.empty() || m_mode == mmMultiExtruder ? + GetParent()->GetBackgroundColour() : + wxColour(colors[m_mode==mmMultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0]); draw_band(dc, clr, main_band); if (m_ticks.empty() || m_mode == mmMultiExtruder) @@ -2972,7 +2974,7 @@ void DoubleSlider::draw_colored_band(wxDC& dc) ++tick_it; continue; } - + draw_band(dc, clr, main_band); ++tick_it; } @@ -3268,6 +3270,62 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) } } +void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu) +{ + const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); + if (extruders_cnt > 1) + { + const int initial_extruder = std::max(1 , get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value)); + + wxMenu* change_extruder_menu = new wxMenu(); + + for (int i = 1; i <= extruders_cnt; i++) + { + const wxString item_name = wxString::Format(_(L("Extruder %d")), i); + + if (m_mode == mmMultiAsSingle) + append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", + [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder); + } + + const wxString change_extruder_menu_name = m_mode == mmMultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); + + wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); + change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, "change_extruder")); + + Slic3r::GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) { + enable_menu_item(evt, [this]() {return m_mode == mmMultiAsSingle; }, change_extruder_menu_item, this); }, + change_extruder_menu_item->GetId()); + } +} + +void DoubleSlider::append_add_color_change_menu_item(wxMenu* menu) +{ + const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); + if (extruders_cnt > 1) + { + std::set used_extruders_for_tick = get_used_extruders_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); + + wxMenu* add_color_change_menu = new wxMenu(); + + for (int i = 1; i <= extruders_cnt; i++) + { + const bool is_used_extruder = used_extruders_for_tick.empty() ? true : // #ys_FIXME till used_extruders_for_tick doesn't filled correct for mmMultiExtruder + used_extruders_for_tick.find(i) != used_extruders_for_tick.end(); + const wxString item_name = wxString::Format(_(L("Extruder %d")), i) + + (is_used_extruder ? "" : " (" + _(L("N/A")) + ")"); + + append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", + [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", menu, + [is_used_extruder]() { return is_used_extruder; }, Slic3r::GUI::wxGetApp().plater()); + } + + const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); + wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); + add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m")); + } +} + void DoubleSlider::OnLeftUp(wxMouseEvent& event) { if (!HasCapture()) @@ -3281,46 +3339,14 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) add_code(Slic3r::ColorChangeCode); else { - const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); - if (extruders_cnt > 1) - { - wxMenu menu; - wxMenu* sub_menu = new wxMenu(); - wxString sub_menu_name = _(L("Change extruder")); - std::string menu_icon_name = "change_extruder"; + wxMenu menu; - if (m_mode == mmMultiAsSingle) - { - int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); - if (initial_extruder == 0) - initial_extruder = 1; + if (m_mode == mmMultiAsSingle) + append_change_extruder_menu_item(&menu); + else + append_add_color_change_menu_item(&menu); - for (int i = /*0*/1; i <= extruders_cnt; i++) { - const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i); - - append_menu_radio_item(sub_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder); - } - } - else - { - for (int i = 1; i <= extruders_cnt; i++) { - const wxString item_name = wxString::Format(_(L("Extruder %d")), i); - - append_menu_item(sub_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu, - [this]() {return true; }, this); - } - - sub_menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); - menu_icon_name = "colorchange_add_m"; - } - - wxMenuItem* sub_menu_item = menu.AppendSubMenu(sub_menu, sub_menu_name, ""); - sub_menu_item->SetBitmap(create_scaled_bitmap(this, menu_icon_name)); - - Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); - } + Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); } m_show_context_menu = false; @@ -3525,8 +3551,9 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) int DoubleSlider::get_extruder_for_tick(int tick) { + int default_initial_extruder = m_mode == mmMultiAsSingle ? m_only_extruder : 0; if (m_ticks.empty()) - return 0; + return default_initial_extruder; auto it = m_ticks.lower_bound(TICK_CODE{tick}); while (it != m_ticks.begin()) { @@ -3535,7 +3562,40 @@ int DoubleSlider::get_extruder_for_tick(int tick) return it->extruder; } - return 0; + return default_initial_extruder; +} + +std::set DoubleSlider::get_used_extruders_for_tick(int tick) +{ + if (m_mode == mmMultiExtruder) + return {}; // #ys_FIXME: correct fill used_extruders_for_tick for mmMultiExtruder + + const int default_initial_extruder = m_mode == mmMultiAsSingle ? std::max(m_only_extruder, 1) : 1; + if (m_ticks.empty()) + return {default_initial_extruder}; + + std::set used_extruders; + + auto it = m_ticks.lower_bound(TICK_CODE{tick}); + while (it != m_ticks.begin()) { + --it; + if(it->gcode == Slic3r::ExtruderChangeCode) + { + used_extruders.emplace(it->extruder); + break; + } + } + if (it == m_ticks.begin()) + used_extruders.emplace(default_initial_extruder); + ++it; + + while (it != m_ticks.end()) { + if(it->gcode == Slic3r::ExtruderChangeCode) + used_extruders.emplace(it->extruder); + ++it; + } + + return used_extruders; } void DoubleSlider::OnRightUp(wxMouseEvent& event) @@ -3554,42 +3614,8 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) [](){return true;}, this); else { - const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); - if (extruders_cnt > 1) - { - int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); - if (initial_extruder == 0) - initial_extruder = 1; - - wxMenu* change_extruder_menu = new wxMenu(); - wxMenu* add_color_change_menu = new wxMenu(); - - for (int i = 1; i <= extruders_cnt; i++) { - const wxString item_name = wxString::Format(_(L("Extruder %d")), i); - - if (m_mode == mmMultiAsSingle) - append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder); - - append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu, - [](){return true;}, this); - } - - const wxString change_extruder_menu_name = m_mode == mmMultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); - - wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); - change_extruder_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "change_extruder")); - - ManipulationMode mode = m_mode; - Slic3r::GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, mode, change_extruder_menu_item](wxUpdateUIEvent& evt) { - enable_menu_item(evt, [this](){return m_mode == mmMultiAsSingle;}, change_extruder_menu_item, this); }, - change_extruder_menu_item->GetId()); - - const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); - wxMenuItem* add_color_change_menu_item = menu.AppendSubMenu(add_color_change_menu, menu_name, ""); - add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m")); - } + append_change_extruder_menu_item(&menu); + append_add_color_change_menu_item(&menu); } append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "", diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 87cc922cf..35357cea4 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -831,6 +831,14 @@ public: void SetManipulationMode(ManipulationMode mode) { m_mode = mode; } ManipulationMode GetManipulationMode() const { return m_mode; } + void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder) + { + m_mode = !is_one_extruder_printed_model ? mmMultiExtruder : + only_extruder < 0 ? mmSingleExtruder : + mmMultiAsSingle; + m_only_extruder = only_extruder; + } + bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } bool is_one_layer() const { return m_is_one_layer; } bool is_lower_at_min() const { return m_lower_value == m_min_value; } @@ -848,7 +856,6 @@ public: void OnKeyUp(wxKeyEvent &event); void OnChar(wxKeyEvent &event); void OnRightDown(wxMouseEvent& event); - int get_extruder_for_tick(int tick); void OnRightUp(wxMouseEvent& event); void add_code(std::string code, int selected_extruder = -1); void edit_tick(); @@ -906,6 +913,12 @@ protected: bool get_color_for_tick( wxColour& color, std::set::const_iterator tick_it, const std::vector& colors) const; + int get_extruder_for_tick(int tick); + std::set get_used_extruders_for_tick(int tick); + + + void append_change_extruder_menu_item(wxMenu*); + void append_add_color_change_menu_item(wxMenu*); private: bool is_osx { false }; @@ -926,7 +939,7 @@ private: ScalableBitmap m_bmp_one_layer_unlock_off; ScalableBitmap m_bmp_revert; ScalableBitmap m_bmp_cog; - SelectedSlider m_selection; + SelectedSlider m_selection; bool m_is_left_down = false; bool m_is_right_down = false; bool m_is_one_layer = false; @@ -941,6 +954,7 @@ private: ManipulationMode m_mode = mmSingleExtruder; std::string m_custom_gcode = ""; std::string m_pause_print_msg; + int m_only_extruder = -1; wxRect m_rect_lower_thumb; wxRect m_rect_higher_thumb; From fdb1d2c9dec923d3b2862a44ee0519348de4bba9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 13 Jan 2020 08:47:11 +0100 Subject: [PATCH 33/85] Follow - up of abd432e7a8f91bba876a29c857844c93dab4b762->Set default as non fullpath export --- src/slic3r/GUI/AppConfig.cpp | 2 +- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index bcd79274f..d277fc095 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -63,7 +63,7 @@ void AppConfig::set_defaults() #if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF if (get("export_sources_full_pathnames").empty()) - set("export_sources_full_pathnames", "1"); + set("export_sources_full_pathnames", "0"); #endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // remove old 'use_legacy_opengl' parameter from this config, if present diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 75d170b03..8a4b28d3a 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -768,7 +768,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) #if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF PageReloadFromDisk::PageReloadFromDisk(ConfigWizard* parent) : ConfigWizardPage(parent, _(L("Reload from disk")), _(L("Reload from disk"))) - , full_pathnames(true) + , full_pathnames(false) { auto* box_pathnames = new wxCheckBox(this, wxID_ANY, _(L("Export full pathnames of models and parts sources into 3mf and amf files"))); box_pathnames->SetValue(wxGetApp().app_config->get("export_sources_full_pathnames") == "1"); From 91acbd01eddbe78c072216bf7f93f5045842e060 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 13 Jan 2020 15:27:37 +0100 Subject: [PATCH 34/85] Fixed GCodeAnalyzer and GCodeTimeEstimator to avoid artifacts while rendering toolpaths due to numerical issues on extruder coordinate --- src/libslic3r/GCode/Analyzer.cpp | 16 ++++++++-------- src/libslic3r/GCodeTimeEstimator.cpp | 4 +++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 7b8004ab0..c70abbbbd 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -311,24 +311,22 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line) { auto axis_absolute_position = [this](GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1) -> float { - float current_absolute_position = _get_axis_position(axis); - float current_origin = _get_axis_origin(axis); - float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f; - bool is_relative = (_get_global_positioning_type() == Relative); if (axis == E) is_relative |= (_get_e_local_positioning_type() == Relative); if (lineG1.has(Slic3r::Axis(axis))) { + float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f; float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor; - return is_relative ? current_absolute_position + ret : ret + current_origin; + return is_relative ? _get_axis_position(axis) + ret : _get_axis_origin(axis) + ret; } else - return current_absolute_position; + return _get_axis_position(axis); }; // updates axes positions from line + float new_pos[Num_Axis]; for (unsigned char a = X; a < Num_Axis; ++a) { @@ -352,7 +350,7 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line) if (delta_pos[E] < 0.0f) { if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) - type = GCodeMove::Move; + type = GCodeMove::Move; else type = GCodeMove::Retract; } @@ -440,7 +438,9 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line) if (line.has_e()) { - _set_axis_origin(E, _get_axis_position(E) - line.e() * lengthsScaleFactor); + // extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments, + // we set the value taken from the G92 line as the new current position for it + _set_axis_position(E, line.e() * lengthsScaleFactor); anyFound = true; } diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index c624c0fce..36127cad7 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -1261,7 +1261,9 @@ namespace Slic3r { if (line.has_e()) { - set_axis_origin(E, get_axis_position(E) - line.e() * lengthsScaleFactor); + // extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments, + // we set the value taken from the G92 line as the new current position for it + set_axis_position(E, line.e() * lengthsScaleFactor); anyFound = true; } else From 19f0f50e9816bbef8f328a4e6d48324c3b44cfd5 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 13 Jan 2020 15:57:31 +0100 Subject: [PATCH 35/85] MSVC specific: Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. Remove this warning disable after eigen library adapts to the new C++17 adaptor rules. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bca5a71a..f31c0eac1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,9 @@ if (MSVC) # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater # Generate symbols at every build target, even for the release. add_compile_options(-bigobj -Zm520 /Zi) + # Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. + #FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules. + add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING) endif () if (MINGW) From 9a3901e159b618e3e708f40b38cb9a883d592902 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 13 Jan 2020 16:01:01 +0100 Subject: [PATCH 36/85] Support for new "default_materials" property at PrinterModel of system profiles. The "default_materials" key accepts "default_filaments" as well. --- src/slic3r/GUI/3DBed.cpp | 18 ++---------------- src/slic3r/GUI/Preset.cpp | 24 ++++++++++++++++++++++++ src/slic3r/GUI/Preset.hpp | 6 ++++++ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index ecbca4228..c66c8efdd 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -341,24 +341,10 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) printf("Unable to create bed grid lines\n"); } -static const VendorProfile::PrinterModel* system_printer_model(const Preset &preset) -{ - const VendorProfile::PrinterModel *out = nullptr; - if (preset.vendor != nullptr) { - auto *printer_model = preset.config.opt("printer_model"); - if (printer_model != nullptr && ! printer_model->value.empty()) { - auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; }); - if (it != preset.vendor->models.end()) - out = &(*it); - } - } - return out; -} - static std::string system_print_bed_model(const Preset &preset) { std::string out; - const VendorProfile::PrinterModel *pm = system_printer_model(preset); + const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset); if (pm != nullptr && ! pm->bed_model.empty()) out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model; return out; @@ -367,7 +353,7 @@ static std::string system_print_bed_model(const Preset &preset) static std::string system_print_bed_texture(const Preset &preset) { std::string out; - const VendorProfile::PrinterModel *pm = system_printer_model(preset); + const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset); if (pm != nullptr && ! pm->bed_texture.empty()) out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture; return out; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index c20a5bb28..b89000891 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -184,6 +184,14 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem } else { BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed variants field: `%2%`") % id % variants_field; } + auto default_materials_field = section.second.get("default_materials", ""); + if (default_materials_field.empty()) + default_materials_field = section.second.get("default_filaments", ""); + if (Slic3r::unescape_strings_cstyle(default_materials_field, model.default_materials)) { + Slic3r::sort_remove_duplicates(model.default_materials); + } else { + BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed default_materials field: `%2%`") % id % default_materials_field; + } model.bed_model = section.second.get("bed_model", ""); model.bed_texture = section.second.get("bed_texture", ""); if (! model.id.empty() && ! model.variants.empty()) @@ -1502,4 +1510,20 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model return it != cend() ? &*it : nullptr; } +namespace PresetUtils { + const VendorProfile::PrinterModel* system_printer_model(const Preset &preset) + { + const VendorProfile::PrinterModel *out = nullptr; + if (preset.vendor != nullptr) { + auto *printer_model = preset.config.opt("printer_model"); + if (printer_model != nullptr && ! printer_model->value.empty()) { + auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; }); + if (it != preset.vendor->models.end()) + out = &(*it); + } + } + return out; + } +} // namespace PresetUtils + } // namespace Slic3r diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 19d07d007..0a26f90cc 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -61,6 +61,7 @@ public: PrinterTechnology technology; std::string family; std::vector variants; + std::vector default_materials; // Vendor & Printer Model specific print bed model & texture. std::string bed_model; std::string bed_texture; @@ -563,6 +564,11 @@ public: const Preset* find_by_model_id(const std::string &model_id) const; }; +namespace PresetUtils { + // PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile. + const VendorProfile::PrinterModel* system_printer_model(const Preset &preset); +} // namespace PresetUtils + } // namespace Slic3r #endif /* slic3r_Preset_hpp_ */ From 36de2c5d90df562e0c7b243c942814090b05dd61 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 13 Jan 2020 17:03:10 +0100 Subject: [PATCH 37/85] Code refactoring for context menus and current extruder color selection for tick --- src/slic3r/GUI/wxExtensions.cpp | 196 ++++++++++++-------------------- src/slic3r/GUI/wxExtensions.hpp | 9 +- 2 files changed, 79 insertions(+), 126 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index a831f32bb..43af0ab7f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2829,96 +2829,38 @@ void DoubleSlider::draw_ticks(wxDC& dc) } } -bool DoubleSlider::get_color_for_tick(wxColour& color, std::set::const_iterator tick_it, const std::vector& colors) const +std::string DoubleSlider::get_color_for_tool_change_tick(std::set::const_iterator it) const { - if (m_mode == mmMultiExtruder) - { - color = GetParent()->GetBackgroundColour(); - return true; + const int current_extruder = it->extruder == 0 ? std::max(m_only_extruder, 1) : it->extruder; + + auto it_n = it; + while (it_n != m_ticks.begin()) { + --it_n; + if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder) + return it_n->color; } - const std::string& code = tick_it->gcode; - if ( code == Slic3r::PausePrintCode || - (code != Slic3r::ColorChangeCode && code != Slic3r::ExtruderChangeCode) ) - return false; + return it->color; +} - if (m_mode == mmSingleExtruder) { - if (code == Slic3r::ColorChangeCode) { - color = wxColour(tick_it->color); - return true; +std::string DoubleSlider::get_color_for_color_change_tick(std::set::const_iterator it) const +{ + const int def_extruder = std::max(1, m_only_extruder); + auto it_n = it; + bool is_tool_change = false; + while (it_n != m_ticks.begin()) { + --it_n; + if (it_n->gcode == Slic3r::ExtruderChangeCode) { + is_tool_change = true; + if (it_n->extruder == it->extruder) + return it->color; + break; } - return false; } + if (!is_tool_change && it->extruder == def_extruder) + return it->color; - const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt(); - const int colors_cnt = colors.size(); - - auto get_m600_color_idx = [extruders_cnt, colors_cnt](const std::set& ticks, std::set::const_iterator it) - { - int shift = 0; - while (it != ticks.begin()) { - --it; - if (it->gcode == Slic3r::ColorChangeCode) - shift++; - } - - if (extruders_cnt + shift >= colors_cnt) - return 0; - return extruders_cnt + shift; - }; - - auto get_color_idx_for_tool_change = [extruders_cnt, colors_cnt, get_m600_color_idx](const std::set& ticks, std::set::const_iterator it) - { - const int current_extruder = it->extruder == 0 ? 1 : it->extruder; - if (extruders_cnt == colors_cnt) // there is no one "M600" - return std::min(extruders_cnt - 1, std::max(current_extruder - 1, 0)); - - auto it_n = it; - while (it_n != ticks.begin()) { - --it_n; - if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder) - return get_m600_color_idx(ticks, it_n); - } - - return std::min(extruders_cnt - 1, std::max(current_extruder - 1, 0)); - }; - - const int extruder = std::max(1, m_only_extruder); - - auto get_color_idx_for_color_change = [get_m600_color_idx, extruder](const std::set& ticks, std::set::const_iterator it) - { - auto it_n = it; - bool is_tool_change = false; - while (it_n != ticks.begin()) { - --it_n; - if (it_n->gcode == Slic3r::ExtruderChangeCode) { - is_tool_change = true; - if (it_n->extruder == it->extruder) - return get_m600_color_idx(ticks, it); - break; - } - } - if (!is_tool_change && it->extruder == extruder) // use correct extruder number instead of 0 - return get_m600_color_idx(ticks, it); - - return -1; - }; - - // change tool (extruder) - if (code == Slic3r::ExtruderChangeCode) - color = wxColour(colors[get_color_idx_for_tool_change(m_ticks, tick_it)]); - - // change color for current extruder - if (code == Slic3r::ColorChangeCode) { - const int color_idx = get_color_idx_for_color_change(m_ticks, tick_it); - if (color_idx < 0) - return false; - if (color_idx >= colors_cnt) - return false; - color = wxColour(colors[color_idx]); - } - - return true; + return ""; } void DoubleSlider::draw_colored_band(wxDC& dc) @@ -2943,39 +2885,35 @@ void DoubleSlider::draw_colored_band(wxDC& dc) dc.DrawRectangle(band_rc); }; - const std::vector& colors = Slic3r::GUI::wxGetApp().plater()->get_colors_for_color_print(); - - wxColour clr = m_ticks.empty() || m_mode == mmMultiExtruder ? - GetParent()->GetBackgroundColour() : - wxColour(colors[m_mode==mmMultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0]); - draw_band(dc, clr, main_band); - + // don't color a band for MultiExtruder mode if (m_ticks.empty() || m_mode == mmMultiExtruder) - // don't color a band for MultiExtruder mode + { + draw_band(dc, GetParent()->GetBackgroundColour(), main_band); return; + } + + const int default_color_idx = m_mode==mmMultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0; + draw_band(dc, wxColour(Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band); std::set::const_iterator tick_it = m_ticks.begin(); while (tick_it != m_ticks.end()) { - if ( (m_mode == mmSingleExtruder && tick_it->gcode != Slic3r::ColorChangeCode ) || - (m_mode == mmMultiAsSingle && !(tick_it->gcode == Slic3r::ExtruderChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) - { - ++tick_it; - continue; + if ( (m_mode == mmSingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) || + (m_mode == mmMultiAsSingle && (tick_it->gcode == Slic3r::ExtruderChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) + { + const wxCoord pos = get_position_from_value(tick_it->tick); + is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) : + main_band.SetBottom(pos - 1); + + const std::string clr_str = m_mode == mmSingleExtruder ? tick_it->color : + tick_it->gcode == Slic3r::ExtruderChangeCode ? + get_color_for_tool_change_tick(tick_it) : + get_color_for_color_change_tick(tick_it); + + if (!clr_str.empty()) + draw_band(dc, wxColour(clr_str), main_band); } - - const wxCoord pos = get_position_from_value(tick_it->tick); - is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) : - main_band.SetBottom(pos - 1); - - if (!get_color_for_tick(clr, tick_it, colors)) - { - ++tick_it; - continue; - } - - draw_band(dc, clr, main_band); ++tick_it; } } @@ -3281,11 +3219,16 @@ void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu) for (int i = 1; i <= extruders_cnt; i++) { - const wxString item_name = wxString::Format(_(L("Extruder %d")), i); + const bool is_active_extruder = i == initial_extruder; + const wxString item_name = wxString::Format(_(L("Extruder %d")), i) + + (is_active_extruder ? " (" + _(L("active")) + ")" : ""); if (m_mode == mmMultiAsSingle) - append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder); + append_menu_item(change_extruder_menu, wxID_ANY, item_name, "", + [this, i](wxCommandEvent&) { change_extruder(i); }, "", menu, + [is_active_extruder]() { return !is_active_extruder; }, Slic3r::GUI::wxGetApp().plater()); +// append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", +// [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder); } const wxString change_extruder_menu_name = m_mode == mmMultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); @@ -3313,7 +3256,7 @@ void DoubleSlider::append_add_color_change_menu_item(wxMenu* menu) const bool is_used_extruder = used_extruders_for_tick.empty() ? true : // #ys_FIXME till used_extruders_for_tick doesn't filled correct for mmMultiExtruder used_extruders_for_tick.find(i) != used_extruders_for_tick.end(); const wxString item_name = wxString::Format(_(L("Extruder %d")), i) + - (is_used_extruder ? "" : " (" + _(L("N/A")) + ")"); + (is_used_extruder ? " (" + _(L("used")) + ")" : ""); append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", menu, @@ -3575,8 +3518,15 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) return {default_initial_extruder}; std::set used_extruders; - - auto it = m_ticks.lower_bound(TICK_CODE{tick}); + auto it_start = m_ticks.lower_bound(TICK_CODE{tick}); + + auto it = it_start; + if (it == m_ticks.begin() && it->gcode == Slic3r::ExtruderChangeCode) { + used_extruders.emplace(it->extruder); + if (tick < it->tick) + used_extruders.emplace(default_initial_extruder); + } + while (it != m_ticks.begin()) { --it; if(it->gcode == Slic3r::ExtruderChangeCode) @@ -3585,10 +3535,11 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) break; } } - if (it == m_ticks.begin()) - used_extruders.emplace(default_initial_extruder); - ++it; + if (it == m_ticks.begin() && used_extruders.empty()) + used_extruders.emplace(default_initial_extruder); + + it = it_start; while (it != m_ticks.end()) { if(it->gcode == Slic3r::ExtruderChangeCode) used_extruders.emplace(it->extruder); @@ -3713,21 +3664,22 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - if (m_mode == mmSingleExtruder && !m_ticks.empty()) { + if (m_ticks.empty()) + color = colors[selected_extruder > 0 ? selected_extruder - 1 : std::max(1, m_only_extruder)-1]; + else + { auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick }); while (before_tick_it != m_ticks.begin()) { --before_tick_it; - if (before_tick_it->gcode == Slic3r::ColorChangeCode) { + if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == selected_extruder) { color = before_tick_it->color; break; } } if (color.empty()) - color = colors[0]; + color = colors[selected_extruder > 0 ? selected_extruder - 1 : std::max(1, m_only_extruder) - 1]; } - else - color = colors[selected_extruder > 0 ? selected_extruder-1 : 0]; color = get_new_color(color); if (color.empty()) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 35357cea4..81f4d7342 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -898,6 +898,8 @@ protected: void action_tick(const TicksAction action); void enter_window(wxMouseEvent& event, const bool enter); +private: + bool is_point_in_rect(const wxPoint& pt, const wxRect& rect); int is_point_near_tick(const wxPoint& pt); @@ -910,9 +912,9 @@ protected: void get_size(int *w, int *h); double get_double_value(const SelectedSlider& selection); wxString get_tooltip(IconFocus icon_focus); - bool get_color_for_tick( wxColour& color, - std::set::const_iterator tick_it, - const std::vector& colors) const; + + std::string get_color_for_tool_change_tick(std::set::const_iterator it) const; + std::string get_color_for_color_change_tick(std::set::const_iterator it) const; int get_extruder_for_tick(int tick); std::set get_used_extruders_for_tick(int tick); @@ -920,7 +922,6 @@ protected: void append_change_extruder_menu_item(wxMenu*); void append_add_color_change_menu_item(wxMenu*); -private: bool is_osx { false }; wxFont m_font; int m_min_value; From 79d7a0130f687a3814d5061cafdf8501338909c0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 13 Jan 2020 17:41:40 +0100 Subject: [PATCH 38/85] Fixing some missing throw statements. Adding noexcept to move constructors / operators. --- src/libslic3r/Config.hpp | 18 +++++++++--------- src/libslic3r/ExPolygon.hpp | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index e7ecc2977..9b04ae026 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -500,7 +500,7 @@ public: if (NULLABLE) this->values.push_back(nil_value()); else - std::runtime_error("Deserializing nil into a non-nullable object"); + throw std::runtime_error("Deserializing nil into a non-nullable object"); } else { std::istringstream iss(item_str); double value; @@ -525,9 +525,9 @@ protected: if (NULLABLE) ss << "nil"; else - std::runtime_error("Serializing NaN"); + throw std::runtime_error("Serializing NaN"); } else - std::runtime_error("Serializing invalid number"); + throw std::runtime_error("Serializing invalid number"); } static bool vectors_equal(const std::vector &v1, const std::vector &v2) { if (NULLABLE) { @@ -646,7 +646,7 @@ public: if (NULLABLE) this->values.push_back(nil_value()); else - std::runtime_error("Deserializing nil into a non-nullable object"); + throw std::runtime_error("Deserializing nil into a non-nullable object"); } else { std::istringstream iss(item_str); int value; @@ -663,7 +663,7 @@ private: if (NULLABLE) ss << "nil"; else - std::runtime_error("Serializing NaN"); + throw std::runtime_error("Serializing NaN"); } else ss << v; } @@ -1126,7 +1126,7 @@ public: if (NULLABLE) this->values.push_back(nil_value()); else - std::runtime_error("Deserializing nil into a non-nullable object"); + throw std::runtime_error("Deserializing nil into a non-nullable object"); } else this->values.push_back(item_str.compare("1") == 0); } @@ -1139,7 +1139,7 @@ protected: if (NULLABLE) ss << "nil"; else - std::runtime_error("Serializing NaN"); + throw std::runtime_error("Serializing NaN"); } else ss << (v ? "1" : "0"); } @@ -1638,7 +1638,7 @@ class DynamicConfig : public virtual ConfigBase public: DynamicConfig() {} DynamicConfig(const DynamicConfig &rhs) { *this = rhs; } - DynamicConfig(DynamicConfig &&rhs) : options(std::move(rhs.options)) { rhs.options.clear(); } + DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); } explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys); explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {} virtual ~DynamicConfig() override { clear(); } @@ -1656,7 +1656,7 @@ public: // Move a content of one DynamicConfig to another DynamicConfig. // If rhs.def() is not null, then it has to be equal to this->def(). - DynamicConfig& operator=(DynamicConfig &&rhs) + DynamicConfig& operator=(DynamicConfig &&rhs) noexcept { assert(this->def() == nullptr || this->def() == rhs.def()); this->clear(); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 4ee8974f4..7c0dfcce5 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -19,7 +19,7 @@ class ExPolygon public: ExPolygon() {} ExPolygon(const ExPolygon &other) : contour(other.contour), holes(other.holes) {} - ExPolygon(ExPolygon &&other) : contour(std::move(other.contour)), holes(std::move(other.holes)) {} + ExPolygon(ExPolygon &&other) noexcept : contour(std::move(other.contour)), holes(std::move(other.holes)) {} explicit ExPolygon(const Polygon &contour) : contour(contour) {} explicit ExPolygon(Polygon &&contour) : contour(std::move(contour)) {} explicit ExPolygon(const Points &contour) : contour(contour) {} @@ -32,7 +32,7 @@ public: ExPolygon(std::initializer_list contour, std::initializer_list hole) : contour(contour), holes({ hole }) {} ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; } - ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; } + ExPolygon& operator=(ExPolygon &&other) noexcept { contour = std::move(other.contour); holes = std::move(other.holes); return *this; } Polygon contour; Polygons holes; From 8bfc986fa7da5dc5676580a4191b0550f3d9e2ab Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 10:31:18 +0100 Subject: [PATCH 39/85] Refactoring of GCode::process_layer(). Refactoring of GCode export of color changes, extruder switches etc, so that the "color change" like extruder switches are applied first at the Wipe Tower / G-code export, so that adding / removing an extruder switch at the G-code preview slider does not invalidate slicing. --- src/libslic3r/Extruder.hpp | 3 - src/libslic3r/GCode.cpp | 365 ++++++++++++-------- src/libslic3r/GCode.hpp | 32 +- src/libslic3r/GCode/ToolOrdering.cpp | 91 +++-- src/libslic3r/GCode/ToolOrdering.hpp | 19 +- src/libslic3r/GCodeWriter.cpp | 10 +- src/libslic3r/GCodeWriter.hpp | 3 +- src/libslic3r/Model.cpp | 28 +- src/libslic3r/Model.hpp | 7 +- src/libslic3r/Print.cpp | 74 +--- src/libslic3r/Print.hpp | 9 - src/slic3r/GUI/BackgroundSlicingProcess.hpp | 5 - src/slic3r/GUI/Plater.cpp | 1 - 13 files changed, 352 insertions(+), 295 deletions(-) diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index df92bf84b..066a5f56d 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -48,9 +48,6 @@ public: double retract_length_toolchange() const; double retract_restart_extra_toolchange() const; - // Constructor for a key object, to be used by the stdlib search functions. - static Extruder key(unsigned int id) { return Extruder(id); } - private: // Private constructor to create a key for a search in std::set. Extruder(unsigned int id) : m_id(id) {} diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 942558f27..5d0a0d4d9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1133,11 +1133,9 @@ void GCode::_do_export(Print& print, FILE* file) m_enable_cooling_markers = true; this->apply_print_config(print.config()); - this->set_extruders(print.extruders()); - // Initialize custom gcode - Model* model = print.get_object(0)->model_object()->get_model(); - m_custom_gcode_per_print_z = model->custom_gcode_per_print_z; + // Initialize custom gcode iterator. + m_custom_gcode_per_print_z_it = print.model().custom_gcode_per_print_z.cbegin(); m_volumetric_speed = DoExport::autospeed_volumetric_limit(print); print.throw_if_canceled(); @@ -1221,18 +1219,27 @@ void GCode::_do_export(Print& print, FILE* file) if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) break; } + // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode. + // Use the extruder IDs collected from Regions. + this->set_extruders(print.extruders()); } else { // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. tool_ordering = print.wipe_tower_data().tool_ordering.empty() ? - ToolOrdering(print, initial_extruder_id) : + ToolOrdering(print, initial_extruder_id, false, + // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. + // Do it only if all the objects were configured to be printed with a single extruder. + (print.object_extruders().size() == 1) ? &custom_tool_changes(print.model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr) : print.wipe_tower_data().tool_ordering; has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); - initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? + initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? // The priming towers will be skipped. tool_ordering.all_extruders().back() : - // Don't skip the priming towers. + // Don't skip the priming towers. tool_ordering.first_extruder(); + // In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z. + // Therefore initialize the printing extruders from there. + this->set_extruders(tool_ordering.all_extruders()); } if (initial_extruder_id == (unsigned int)-1) { // Nothing to print! @@ -1247,7 +1254,7 @@ void GCode::_do_export(Print& print, FILE* file) // #ys_FIXME_no_exported_codes /* /* To avoid change filament for non-used extruder for Multi-material, - * check model->custom_gcode_per_print_z using tool_ordering values + * check print.model().custom_gcode_per_print_z using tool_ordering values * / if (!m_custom_gcode_per_print_z. empty()) { @@ -1283,7 +1290,7 @@ void GCode::_do_export(Print& print, FILE* file) } if (delete_executed) - model->custom_gcode_per_print_z = m_custom_gcode_per_print_z; + print.model().custom_gcode_per_print_z = m_custom_gcode_per_print_z; } */ @@ -1768,6 +1775,174 @@ std::vector GCode::sort_print_object_instances( return out; } +namespace ProcessLayer +{ + + std::string emit_custom_gcode_per_print_z( + // Last processed CustomGCode. + std::vector::const_iterator &custom_gcode_per_print_z_it, + const std::vector::const_iterator custom_gcode_per_print_z_end, + // This layer's print_z. + coordf_t current_print_z, + // ID of the first extruder printing this layer. + unsigned int first_extruder_id, + size_t num_extruders) + { + // Let's issue a filament change command if requested at this layer. + // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. + // (Layers can be close to each other, model could have been resliced with bigger layer height, ...). + bool has_colorchange = false; + + std::string custom_code; + std::string pause_print_msg; + int m600_before_extruder = -1; + while (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end) { + auto it_next = custom_gcode_per_print_z_it; + if ((++ it_next)->print_z >= current_print_z + EPSILON) + break; + custom_gcode_per_print_z_it = it_next; + } + if (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end && custom_gcode_per_print_z_it->print_z < current_print_z + EPSILON) { + custom_code = custom_gcode_per_print_z_it->gcode; + + if (custom_code == ColorChangeCode && custom_gcode_per_print_z_it->extruder > 0) + m600_before_extruder = custom_gcode_per_print_z_it->extruder - 1; + if (custom_code == PausePrintCode) + pause_print_msg = custom_gcode_per_print_z_it->color; + + // This color change is consumed, don't use it again. + ++ custom_gcode_per_print_z_it; + has_colorchange = true; + } + + // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count + + // don't save "tool_change"(ExtruderChangeCode) code to GCode + std::string gcode; + if (has_colorchange && custom_code != ExtruderChangeCode) { + const bool single_material_print = num_extruders == 1; + + if (custom_code == ColorChangeCode) // color change + { + // add tag for analyzer + gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n"; + // add tag for time estimator + gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; + + if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder + // && !MMU1 + ) { + //! FIXME_in_fw show message during print pause + gcode += "M601\n"; // pause print + gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n"; + } + else + gcode += custom_code + "\n"; + } + else + { + if (custom_code == PausePrintCode) // Pause print + { + // add tag for analyzer + gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n"; + //! FIXME_in_fw show message during print pause + if (!pause_print_msg.empty()) + gcode += "M117 " + pause_print_msg + "\n"; + // add tag for time estimator + //gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n"; + } + else // custom Gcode + { + // add tag for analyzer + gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n"; + // add tag for time estimator + //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n"; + } + gcode += custom_code + "\n"; + } + } + + return gcode; + } +} // namespace ProcessLayer + +namespace Skirt { + std::map> make_skirt_loops_per_extruder_1st_layer( + const Print &print, + const std::vector &layers, + const LayerTools &layer_tools, + std::vector extruder_ids, + // Heights at which the skirt has already been extruded. + std::vector &skirt_done) + { + // Extrude skirt at the print_z of the raft layers and normal object layers + // not at the print_z of the interlaced support material layers. + std::map> skirt_loops_per_extruder_out; + assert(skirt_done.empty()); + if (print.has_skirt() && ! print.skirt().entities.empty()) { + // Prime all the printing extruders over the skirt lines. + // Reorder the extruders, so that the last used extruder is at the front. + unsigned int first_extruder_id = layer_tools.extruders.front(); + for (size_t i = 1; i < extruder_ids.size(); ++ i) + if (extruder_ids[i] == first_extruder_id) { + // Move the last extruder to the front. + memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int)); + extruder_ids.front() = first_extruder_id; + break; + } + size_t n_loops = print.skirt().entities.size(); + if (n_loops <= extruder_ids.size()) { + for (size_t i = 0; i < n_loops; ++i) + skirt_loops_per_extruder_out[extruder_ids[i]] = std::pair(i, i + 1); + } else { + // Assign skirt loops to the extruders. + std::vector extruder_loops(extruder_ids.size(), 1); + n_loops -= extruder_loops.size(); + while (n_loops > 0) { + for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++i, --n_loops) + ++extruder_loops[i]; + } + for (size_t i = 0; i < extruder_ids.size(); ++i) + skirt_loops_per_extruder_out[extruder_ids[i]] = std::make_pair( + (i == 0) ? 0 : extruder_loops[i - 1], + ((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]); + } + skirt_done.emplace_back(layer_tools.print_z - (skirt_done.empty() ? 0. : skirt_done.back())); + + } + return skirt_loops_per_extruder_out; + } + + std::map> make_skirt_loops_per_extruder_other_layers( + const Print &print, + const std::vector &layers, + const LayerTools &layer_tools, + // Heights at which the skirt has already been extruded. + std::vector &skirt_done) + { + // Extrude skirt at the print_z of the raft layers and normal object layers + // not at the print_z of the interlaced support material layers. + std::map> skirt_loops_per_extruder_out; + if (print.has_skirt() && ! print.skirt().entities.empty() && + // Not enough skirt layers printed yet. + //FIXME infinite or high skirt does not make sense for sequential print! + (skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) && + // This print_z has not been extruded yet + skirt_done.back() < layer_tools.print_z - EPSILON && + // and this layer is an object layer, or it is a raft layer. + //FIXME one uses the number of raft layers from the 1st object! + (layer_tools.has_object || layers.front().support_layer->id() < (size_t)layers.front().support_layer->object()->config().raft_layers.value)) { + // Extrude all skirts with the current extruder. + unsigned int first_extruder_id = layer_tools.extruders.front(); + skirt_loops_per_extruder_out[first_extruder_id] = std::pair(0, print.config().skirts.value); + assert(!skirt_done.empty()); + skirt_done.emplace_back(layer_tools.print_z - skirt_done.back()); + } + return skirt_loops_per_extruder_out; + } + +} // namespace Skirt + // In sequential mode, process_layer is called once per each object and its copy, // therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object. // In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated. @@ -1804,7 +1979,7 @@ void GCode::process_layer( if (l.support_layer != nullptr && support_layer == nullptr) support_layer = l.support_layer; } - const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer; + const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer; coordf_t print_z = layer.print_z; bool first_layer = layer.id() == 0; unsigned int first_extruder_id = layer_tools.extruders.front(); @@ -1868,120 +2043,21 @@ void GCode::process_layer( m_second_layer_things_done = true; } - // Let's issue a filament change command if requested at this layer. - // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. - // (Layers can be close to each other, model could have been resliced with bigger layer height, ...). - bool colorprint_change = false; - - std::string custom_code = ""; - std::string pause_print_msg = ""; - int m600_before_extruder = -1; - while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) { - custom_code = m_custom_gcode_per_print_z.front().gcode; - - if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0) - m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1; - if (custom_code == PausePrintCode) - pause_print_msg = m_custom_gcode_per_print_z.front().color; - - m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin()); - colorprint_change = true; - } - - // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count - - // don't save "tool_change"(ExtruderChangeCode) code to GCode - if (colorprint_change && custom_code != ExtruderChangeCode) { - const bool single_material_print = print.config().nozzle_diameter.size() == 1; - - if (custom_code == ColorChangeCode) // color change - { - // add tag for analyzer - gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n"; - // add tag for time estimator - gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; - - if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder - // && !MMU1 - ) { - //! FIXME_in_fw show message during print pause - gcode += "M601\n"; // pause print - gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n"; - } - else - gcode += custom_code + "\n"; - } - else - { - if (custom_code == PausePrintCode) // Pause print - { - // add tag for analyzer - gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n"; - //! FIXME_in_fw show message during print pause - if (!pause_print_msg.empty()) - gcode += "M117 " + pause_print_msg + "\n"; - // add tag for time estimator - //gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n"; - } - else // custom Gcode - { - // add tag for analyzer - gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n"; - // add tag for time estimator - //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n"; - } - gcode += custom_code + "\n"; - } - } - - - // Extrude skirt at the print_z of the raft layers and normal object layers - // not at the print_z of the interlaced support material layers. - bool extrude_skirt = - ! print.skirt().entities.empty() && - // Not enough skirt layers printed yet. - (m_skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) && - // This print_z has not been extruded yet - (m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON && - // and this layer is the 1st layer, or it is an object layer, or it is a raft layer. - (first_layer || object_layer != nullptr || support_layer->id() < (size_t)m_config.raft_layers.value); + // Map from extruder ID to index of skirt loops to be extruded with that extruder. std::map> skirt_loops_per_extruder; - coordf_t skirt_height = 0.; - if (extrude_skirt) { - // Fill in skirt_loops_per_extruder. - skirt_height = print_z - (m_skirt_done.empty() ? 0. : m_skirt_done.back()); - m_skirt_done.push_back(print_z); - if (first_layer) { - // Prime the extruders over the skirt lines. - std::vector extruder_ids = m_writer.extruder_ids(); - // Reorder the extruders, so that the last used extruder is at the front. - for (size_t i = 1; i < extruder_ids.size(); ++ i) - if (extruder_ids[i] == first_extruder_id) { - // Move the last extruder to the front. - memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int)); - extruder_ids.front() = first_extruder_id; - break; - } - size_t n_loops = print.skirt().entities.size(); - if (n_loops <= extruder_ids.size()) { - for (size_t i = 0; i < n_loops; ++i) - skirt_loops_per_extruder[extruder_ids[i]] = std::pair(i, i + 1); - } else { - // Assign skirt loops to the extruders. - std::vector extruder_loops(extruder_ids.size(), 1); - n_loops -= extruder_loops.size(); - while (n_loops > 0) { - for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++ i, -- n_loops) - ++ extruder_loops[i]; - } - for (size_t i = 0; i < extruder_ids.size(); ++ i) - skirt_loops_per_extruder[extruder_ids[i]] = std::make_pair( - (i == 0) ? 0 : extruder_loops[i - 1], - ((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]); - } - } else - // Extrude all skirts with the current extruder. - skirt_loops_per_extruder[first_extruder_id] = std::pair(0, print.config().skirts.value); + + if (single_object_instance_idx == size_t(-1) && object_layer != nullptr) { + // Normal (non-sequential) print. + gcode += ProcessLayer::emit_custom_gcode_per_print_z( + // input / output + m_custom_gcode_per_print_z_it, + // inputs + print.model().custom_gcode_per_print_z.cend(), layer.print_z, first_extruder_id, print.config().nozzle_diameter.size()); + // Extrude skirt at the print_z of the raft layers and normal object layers + // not at the print_z of the interlaced support material layers. + skirt_loops_per_extruder = first_layer ? + Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_writer.extruder_ids(), m_skirt_done) : + Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done); } // Group extrusions by an extruder, then by an object, an island and a region. @@ -2085,7 +2161,7 @@ void GCode::process_layer( continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - int correct_extruder_id = Print::get_extruder(*extrusions, region); + int correct_extruder_id = layer_tools.extruder(*extrusions, region); // Let's recover vector of extruder overrides: const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr; @@ -2152,30 +2228,27 @@ void GCode::process_layer( if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower) m_last_analyzer_extrusion_role = erWipeTower; - if (extrude_skirt) { - auto loops_it = skirt_loops_per_extruder.find(extruder_id); - if (loops_it != skirt_loops_per_extruder.end()) { - const std::pair loops = loops_it->second; - this->set_origin(0.,0.); - m_avoid_crossing_perimeters.use_external_mp = true; - Flow skirt_flow = print.skirt_flow(); - for (size_t i = loops.first; i < loops.second; ++ i) { - // Adjust flow according to this layer's layer height. - ExtrusionLoop loop = *dynamic_cast(print.skirt().entities[i]); - Flow layer_skirt_flow(skirt_flow); - layer_skirt_flow.height = (float)skirt_height; - double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); - for (ExtrusionPath &path : loop.paths) { - path.height = (float)layer.height; - path.mm3_per_mm = mm3_per_mm; - } - gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value); + if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { + const std::pair loops = loops_it->second; + this->set_origin(0., 0.); + m_avoid_crossing_perimeters.use_external_mp = true; + Flow layer_skirt_flow(print.skirt_flow()); + layer_skirt_flow.height = (float)(m_skirt_done.back() - ((m_skirt_done.size() == 1) ? 0. : m_skirt_done[m_skirt_done.size() - 2])); + double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); + for (size_t i = loops.first; i < loops.second; ++i) { + // Adjust flow according to this layer's layer height. + ExtrusionLoop loop = *dynamic_cast(print.skirt().entities[i]); + for (ExtrusionPath &path : loop.paths) { + path.height = layer_skirt_flow.height; + path.mm3_per_mm = mm3_per_mm; } - m_avoid_crossing_perimeters.use_external_mp = false; - // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers). - if (first_layer && loops.first == 0) - m_avoid_crossing_perimeters.disable_once = true; + //FIXME using the support_material_speed of the 1st object printed. + gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value); } + m_avoid_crossing_perimeters.use_external_mp = false; + // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers). + if (first_layer && loops.first == 0) + m_avoid_crossing_perimeters.disable_once = true; } // Extrude brim with the extruder of the 1st region. diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index d5213d00b..10644a60b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -197,23 +197,25 @@ public: // append full config to the given string static void append_full_config(const Print& print, std::string& str); + // Object and support extrusions of the same PrintObject at the same print_z. + // public, so that it could be accessed by free helper functions from GCode.cpp + struct LayerToPrint + { + LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {} + const Layer* object_layer; + const SupportLayer* support_layer; + const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; } + const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; } + coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; } + }; + private: #if ENABLE_THUMBNAIL_GENERATOR - void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb); + void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb); #else void _do_export(Print &print, FILE *file); #endif //ENABLE_THUMBNAIL_GENERATOR - // Object and support extrusions of the same PrintObject at the same print_z. - struct LayerToPrint - { - LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {} - const Layer *object_layer; - const SupportLayer *support_layer; - const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; } - const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; } - coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; } - }; static std::vector collect_layers_to_print(const PrintObject &object); static std::vector>> collect_layers_to_print(const Print &print); void process_layer( @@ -372,11 +374,9 @@ private: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; - // Extensions for colorprint - now it's not a just color_print_heights, - // there can be some custom gcode. - // Updated before the export and erased during the process, - // so no toolchange occurs twice. - std::vector m_custom_gcode_per_print_z; + // Iterator to Model::custom_gcode_per_print_z, which is being increased by process_layer. + // The Model::custom_gcode_per_print_z may contain color changes, extruder switches, pauses and custom G-codes. + std::vector::const_iterator m_custom_gcode_per_print_z_it; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 8aed420cb..3edb7cf17 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -34,6 +34,39 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const return false; } +// Return a zero based extruder from the region, or extruder_override if overriden. +unsigned int LayerTools::perimeter_extruder(const PrintRegion ®ion) const +{ + assert(region.config().perimeter_extruder.value > 0); + return ((this->extruder_override == 0) ? region.config().perimeter_extruder.value : this->extruder_override) - 1; +} + +unsigned int LayerTools::infill_extruder(const PrintRegion ®ion) const +{ + assert(region.config().infill_extruder.value > 0); + return ((this->extruder_override == 0) ? region.config().infill_extruder.value : this->extruder_override) - 1; +} + +unsigned int LayerTools::solid_infill_extruder(const PrintRegion ®ion) const +{ + assert(region.config().solid_infill_extruder.value > 0); + return ((this->extruder_override == 0) ? region.config().solid_infill_extruder.value : this->extruder_override) - 1; +} + +// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden. +unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const +{ + assert(region.config().perimeter_extruder.value > 0); + assert(region.config().infill_extruder.value > 0); + assert(region.config().solid_infill_extruder.value > 0); + // 1 based extruder ID. + unsigned int extruder = ((this->extruder_override == 0) ? + (is_infill(extrusions.role()) ? + (is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) : + region.config().perimeter_extruder.value) : + this->extruder_override); + return (extruder == 0) ? 0 : extruder - 1; +} // For the use case when each object is printed separately // (print.config().complete_objects is true). @@ -54,7 +87,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude } // Collect extruders reuqired to print the layers. - this->collect_extruders(object); + this->collect_extruders(object, nullptr); // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); @@ -66,7 +99,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // For the use case when all objects are printed at once. // (print.config().complete_objects is false). -ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) +ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material, const std::vector> *per_layer_extruder_switches) { m_print_config_ptr = &print.config(); @@ -93,7 +126,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool // Collect extruders reuqired to print the layers. for (auto object : print.objects()) - this->collect_extruders(*object); + this->collect_extruders(*object, (per_layer_extruder_switches != nullptr && ! per_layer_extruder_switches->empty()) ? per_layer_extruder_switches : nullptr); // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); @@ -119,7 +152,7 @@ void ToolOrdering::initialize_layers(std::vector &zs) } // Collect extruders reuqired to print layers. -void ToolOrdering::collect_extruders(const PrintObject &object) +void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector> *per_layer_extruder_switches) { // Collect the support extruders. for (auto support_layer : object.support_layers()) { @@ -136,9 +169,25 @@ void ToolOrdering::collect_extruders(const PrintObject &object) if (has_support || has_interface) layer_tools.has_support = true; } + + // Extruder overrides are ordered by print_z. + std::vector>::const_iterator it_per_layer_extruder_override; + if (per_layer_extruder_switches != nullptr) + it_per_layer_extruder_override = per_layer_extruder_switches->begin(); + unsigned int extruder_override = 0; + // Collect the object extruders. for (auto layer : object.layers()) { LayerTools &layer_tools = this->tools_for_layer(layer->print_z); + + // Override extruder with the next + if (per_layer_extruder_switches != nullptr) + for (; it_per_layer_extruder_override != per_layer_extruder_switches->end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override) + extruder_override = (int)it_per_layer_extruder_override->second; + + // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it. + layer_tools.extruder_override = extruder_override; + // What extruders are required to print this object layer? for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) { const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; @@ -159,12 +208,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object) } if (something_nonoverriddable) - layer_tools.extruders.push_back(region.config().perimeter_extruder.value); + layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().perimeter_extruder.value : extruder_override); layer_tools.has_object = true; } - bool has_infill = false; bool has_solid_infill = false; bool something_nonoverriddable = false; @@ -183,12 +231,14 @@ void ToolOrdering::collect_extruders(const PrintObject &object) } } - if (something_nonoverriddable || !m_print_config_ptr) - { - if (has_solid_infill) - layer_tools.extruders.push_back(region.config().solid_infill_extruder); - if (has_infill) - layer_tools.extruders.push_back(region.config().infill_extruder); + if (something_nonoverriddable || !m_print_config_ptr) { + if (extruder_override == 0) { + if (has_solid_infill) + layer_tools.extruders.emplace_back(region.config().solid_infill_extruder); + if (has_infill) + layer_tools.extruders.emplace_back(region.config().infill_extruder); + } else if (has_solid_infill || has_infill) + layer_tools.extruders.emplace_back(extruder_override); } if (has_solid_infill || has_infill) layer_tools.has_object = true; @@ -201,7 +251,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) // make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) if (layer.extruders.empty() && layer.has_object) - layer.extruders.push_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders + layer.extruders.emplace_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders } } @@ -256,11 +306,9 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id) for (unsigned int &extruder_id : lt.extruders) { assert(extruder_id > 0); -- extruder_id; - } + } } - - void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z) { if (m_layer_tools.empty()) @@ -413,7 +461,7 @@ const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const } // This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual) -void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) +void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies) { something_overridden = true; @@ -449,11 +497,10 @@ int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print return (-1); } - // Decides whether this entity could be overridden bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const { - if (print_config.filament_soluble.get_at(Print::get_extruder(eec, region))) + if (print_config.filament_soluble.get_at(m_layer_tools->extruder(eec, region))) return false; if (object.config().wipe_into_objects) @@ -522,7 +569,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if (wipe_into_infill_only && ! print.config().infill_first) // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): - if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder)) + if (!lt.is_extruder_order(lt.perimeter_extruder(region), new_extruder)) continue; if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder @@ -597,8 +644,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) // Either way, we will now force-override it with something suitable: if (print.config().infill_first || object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely - || lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints - || ! lt.has_extruder(region.config().infill_extruder - 1))) // we have to force override - this could violate infill_first (FIXME) + || lt.is_extruder_order(lt.perimeter_extruder(region), last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints + || ! lt.has_extruder(lt.infill_extruder(region)))) // we have to force override - this could violate infill_first (FIXME) set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); else { // In this case we can (and should) leave it to be printed normally. diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index ed7aaab43..1f043d94f 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -61,7 +61,7 @@ private: int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const; // This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) - void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); + void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies); // Returns true in case that entity is not printed with its usual extruder for a given copy: bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const { @@ -84,6 +84,7 @@ public: print_z(z), has_object(false), has_support(false), + extruder_override(0), has_wipe_tower(false), wipe_tower_partitions(0), wipe_tower_layer_height(0.) {} @@ -96,11 +97,21 @@ public: bool is_extruder_order(unsigned int a, unsigned int b) const; bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); } + // Return a zero based extruder from the region, or extruder_override if overriden. + unsigned int perimeter_extruder(const PrintRegion ®ion) const; + unsigned int infill_extruder(const PrintRegion ®ion) const; + unsigned int solid_infill_extruder(const PrintRegion ®ion) const; + // Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden. + unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const; + coordf_t print_z; bool has_object; bool has_support; // Zero based extruder IDs, ordered to minimize tool switches. std::vector extruders; + // If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with. + // If not overriden, it is set to 0. + unsigned int extruder_override; // Will there be anything extruded on this layer for the wipe tower? // Due to the support layers possibly interleaving the object layers, // wipe tower will be disabled for some support only layers. @@ -129,11 +140,11 @@ public: // For the use case when each object is printed separately // (print.config.complete_objects is true). - ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false); // For the use case when all objects are printed at once. // (print.config.complete_objects is false). - ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false, const std::vector> *per_layer_extruder_switches = nullptr); void clear() { m_layer_tools.clear(); } @@ -160,7 +171,7 @@ public: private: void initialize_layers(std::vector &zs); - void collect_extruders(const PrintObject &object); + void collect_extruders(const PrintObject &object, const std::vector> *per_layer_extruder_switches); void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 364ba12ae..0266eee39 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -19,8 +19,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) this->config.apply(print_config, true); m_extrusion_axis = this->config.get_extrusion_axis(); m_single_extruder_multi_material = print_config.single_extruder_multi_material.value; - m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ? - print_config.machine_max_acceleration_extruding.values.front() : 0; + m_max_acceleration = std::lrint((print_config.gcode_flavor.value == gcfMarlin) ? + print_config.machine_max_acceleration_extruding.values.front() : 0); } void GCodeWriter::set_extruders(const std::vector &extruder_ids) @@ -247,9 +247,9 @@ std::string GCodeWriter::toolchange_prefix() const std::string GCodeWriter::toolchange(unsigned int extruder_id) { // set the new extruder - auto it_extruder = std::lower_bound(m_extruders.begin(), m_extruders.end(), Extruder::key(extruder_id)); - assert(it_extruder != m_extruders.end()); - m_extruder = const_cast(&*it_extruder); + auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; }); + assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id); + m_extruder = &*it_extruder; // return the toolchange command // if we are running a single-extruder setup, just set the extruder and return nothing diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 98abdda28..1631d8590 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -74,7 +74,8 @@ public: Vec3d get_position() const { return m_pos; } private: - std::vector m_extruders; + // Extruders are sorted by their ID, so that binary search is possible. + std::vector m_extruders; std::string m_extrusion_axis; bool m_single_extruder_multi_material; Extruder* m_extruder; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 96a32680e..812180641 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -598,21 +598,6 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte return boost::filesystem::path(this->propose_export_file_name_and_path()).replace_extension(new_extension).string(); } -std::vector> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const -{ - std::vector> custom_tool_changes; - for (const CustomGCode& custom_gcode : custom_gcode_per_print_z) - if (custom_gcode.gcode == ExtruderChangeCode) { - DynamicPrintConfig config; - // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders - config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder)); - // For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height - custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config }); - } - - return custom_tool_changes; -} - ModelObject::~ModelObject() { this->clear_volumes(); @@ -1856,6 +1841,19 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const return ret; } +// Return pairs of sorted by increasing print_z from custom_gcode_per_print_z. +// print_z corresponds to the first layer printed with the new extruder. +std::vector> custom_tool_changes(const Model &model, size_t num_extruders) +{ + std::vector> custom_tool_changes; + for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z) + if (custom_gcode.gcode == ExtruderChangeCode) { + // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders + custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder)); + } + return custom_tool_changes; +} + // Test whether the two models contain the same number of ModelObjects with the same set of IDs // ordered in the same order. In that case it is not necessary to kill the background processing. bool model_object_list_equal(const Model &model_old, const Model &model_new) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 44f5049c9..26bb4cb92 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -838,9 +838,6 @@ public: // Propose an output path, replace extension. The new_extension shall contain the initial dot. std::string propose_export_file_name_and_path(const std::string &new_extension) const; - // from custom_gcode_per_print_z get just tool_change codes - std::vector> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const; - private: explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }; void assign_new_unique_ids_recursive(); @@ -857,6 +854,10 @@ private: #undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE #undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE +// Return pairs of sorted by increasing print_z from custom_gcode_per_print_z. +// print_z corresponds to the first layer printed with the new extruder. +extern std::vector> custom_tool_changes(const Model &model, size_t num_extruders); + // Test whether the two models contain the same number of ModelObjects with the same set of IDs // ordered in the same order. In that case it is not necessary to kill the background processing. extern bool model_object_list_equal(const Model &model_old, const Model &model_new); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 02d9da784..2d327c70b 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -638,48 +638,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr); } - // Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs, - // considering custom_tool_change values - void assign(const t_layer_config_ranges &in, const std::vector> &custom_tool_changes) { - m_ranges.clear(); - m_ranges.reserve(in.size()); - // Input ranges are sorted lexicographically. First range trims the other ranges. - coordf_t last_z = 0; - for (const std::pair &range : in) - if (range.first.second > last_z) { - coordf_t min_z = std::max(range.first.first, 0.); - if (min_z > last_z + EPSILON) { - m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr); - last_z = min_z; - } - if (range.first.second > last_z + EPSILON) { - const DynamicPrintConfig* cfg = &range.second; - m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg); - last_z = range.first.second; - } - } - - // add ranges for extruder changes from custom_tool_changes - for (size_t i = 0; i < custom_tool_changes.size(); i++) { - const DynamicPrintConfig* cfg = &custom_tool_changes[i].second; - coordf_t cur_Z = custom_tool_changes[i].first; - coordf_t next_Z = i == custom_tool_changes.size()-1 ? DBL_MAX : custom_tool_changes[i+1].first; - if (cur_Z > last_z + EPSILON) { - if (i==0) - m_ranges.emplace_back(t_layer_height_range(last_z, cur_Z), nullptr); - m_ranges.emplace_back(t_layer_height_range(cur_Z, next_Z), cfg); - } - else if (next_Z > last_z + EPSILON) - m_ranges.emplace_back(t_layer_height_range(last_z, next_Z), cfg); - } - - if (m_ranges.empty()) - m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr); - else if (m_ranges.back().second == nullptr) - m_ranges.back().first.second = DBL_MAX; - else if (m_ranges.back().first.second != DBL_MAX) - m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr); - } const DynamicPrintConfig* config(const t_layer_height_range &range) const { auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr)); // #ys_FIXME_COLOR @@ -733,17 +691,15 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::New); } else { + if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) { + // If custom gcode per layer height was changed, we should stop background processing. + update_apply_status(this->invalidate_steps({ psWipeTower, psGCodeExport })); + m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; + } if (model_object_list_equal(m_model, model)) { // The object list did not change. for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); - - // But if custom gcode per layer height was changed - if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) { - // we should stop background processing - update_apply_status(this->invalidate_step(psGCodeExport)); - m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; - } } else if (model_object_list_extended(m_model, model)) { // Add new objects. Their volumes and configs will be synchronized later. update_apply_status(this->invalidate_step(psGCodeExport)); @@ -835,9 +791,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ for (PrintObject *print_object : m_objects) print_object_status.emplace(PrintObjectStatus(print_object)); - std::vector> custom_tool_changes = - m_model.get_custom_tool_changes(m_default_object_config.layer_height, num_extruders); - // 3) Synchronize ModelObjects & PrintObjects. for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) { ModelObject &model_object = *m_model.objects[idx_model_object]; @@ -845,9 +798,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ assert(it_status != model_object_status.end()); assert(it_status->status != ModelObjectStatus::Deleted); const ModelObject& model_object_new = *model.objects[idx_model_object]; - // ys_FIXME_COLOR - // const_cast(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges); - const_cast(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges, custom_tool_changes); + const_cast(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges); if (it_status->status == ModelObjectStatus::New) // PrintObject instances will be added in the next loop. continue; @@ -1015,8 +966,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ PrintRegionConfig this_region_config; bool this_region_config_set = false; for (PrintObject *print_object : m_objects) { - if(m_force_update_print_regions && !custom_tool_changes.empty()) - goto print_object_end; const LayerRanges *layer_ranges; { auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id())); @@ -1989,7 +1938,9 @@ void Print::_make_wipe_tower() wipe_volumes.push_back(std::vector(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. - m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); + m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true, + (this->object_extruders().size() == 1) ? &custom_tool_changes(this->model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr); + if (! m_wipe_tower_data.tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. return; @@ -2107,13 +2058,6 @@ void Print::_make_wipe_tower() m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); } -// Returns extruder this eec should be printed with, according to PrintRegion config -int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) -{ - return is_infill(fill.role()) ? std::max(0, (is_solid_infill(fill.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) : - std::max(region.config().perimeter_extruder.value - 1, 0); -} - // Generate a recommended G-code output file name based on the format template, default extension, and template parameters // (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics. // Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before G-code is finalized). diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index c434eec43..89d27e3cb 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -369,9 +369,6 @@ public: // If zero, then the print is empty and the print shall not be executed. unsigned int num_object_instances() const; - // Returns extruder this eec should be printed with, according to PrintRegion config: - static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); - const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } @@ -386,9 +383,6 @@ public: // Accessed by SupportMaterial const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } - // force update of PrintRegions, when custom_tool_change is not empty and (Re)Slicing is started - void set_force_update_print_regions(bool force_update_print_regions) { m_force_update_print_regions = force_update_print_regions; } - protected: // methods for handling regions PrintRegion* get_region(size_t idx) { return m_regions[idx]; } @@ -431,9 +425,6 @@ private: // Estimated print time, filament consumed. PrintStatistics m_print_statistics; - // flag used - bool m_force_update_print_regions = false; - // To allow GCode to set the Print's GCodeExport step status. friend class GCode; // Allow PrintObject to access m_mutex and m_cancel_callback. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index a66dcf39c..984686e35 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -132,11 +132,6 @@ public: // This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs), // and it does not account for the OctoPrint scheduling. bool finished() const { return m_print->finished(); } - - void set_force_update_print_regions(bool force_update_print_regions) { - if (m_fff_print) - m_fff_print->set_force_update_print_regions(force_update_print_regions); - } private: void thread_proc(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 011d7e7ce..dc720ddae 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3022,7 +3022,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool this->update_print_volume_state(); // Apply new config to the possibly running background task. bool was_running = this->background_process.running(); - this->background_process.set_force_update_print_regions(force_validation); Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config()); // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. From 98e49772ed7aaec45dacfc4dd75a06ec41cd2add Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 11:54:09 +0100 Subject: [PATCH 40/85] Custom G-code references are now being assigned to ToolOrdering::LayerTools() and the superfluous M600 (color change) events are filtered out there. Fixed a handful of compiler warnings. --- src/libslic3r/Flow.cpp | 4 +- src/libslic3r/GCode.cpp | 118 +++++--------------------- src/libslic3r/GCode.hpp | 3 - src/libslic3r/GCode/Analyzer.cpp | 2 +- src/libslic3r/GCode/CoolingBuffer.cpp | 4 +- src/libslic3r/GCode/PrintExtents.cpp | 6 +- src/libslic3r/GCode/ToolOrdering.cpp | 58 ++++++++++++- src/libslic3r/GCode/ToolOrdering.hpp | 29 +++---- src/libslic3r/Print.cpp | 7 +- 9 files changed, 100 insertions(+), 131 deletions(-) diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 6069677a1..2c5c64fe7 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -107,9 +107,9 @@ double Flow::mm3_per_mm() const { float res = this->bridge ? // Area of a circle with dmr of this->width. - (this->width * this->width) * 0.25 * PI : + float((this->width * this->width) * 0.25 * PI) : // Rectangle with semicircles at the ends. ~ h (w - 0.215 h) - this->height * (this->width - this->height * (1. - 0.25 * PI)); + float(this->height * (this->width - this->height * (1. - 0.25 * PI))); //assert(res > 0.); if (res <= 0.) throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?"); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5d0a0d4d9..6fa145bf6 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1134,9 +1134,6 @@ void GCode::_do_export(Print& print, FILE* file) m_enable_cooling_markers = true; this->apply_print_config(print.config()); - // Initialize custom gcode iterator. - m_custom_gcode_per_print_z_it = print.model().custom_gcode_per_print_z.cbegin(); - m_volumetric_speed = DoExport::autospeed_volumetric_limit(print); print.throw_if_canceled(); @@ -1226,10 +1223,7 @@ void GCode::_do_export(Print& print, FILE* file) // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. tool_ordering = print.wipe_tower_data().tool_ordering.empty() ? - ToolOrdering(print, initial_extruder_id, false, - // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. - // Do it only if all the objects were configured to be printed with a single extruder. - (print.object_extruders().size() == 1) ? &custom_tool_changes(print.model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr) : + ToolOrdering(print, initial_extruder_id, false) : print.wipe_tower_data().tool_ordering; has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? @@ -1251,49 +1245,6 @@ void GCode::_do_export(Print& print, FILE* file) } print.throw_if_canceled(); -// #ys_FIXME_no_exported_codes - /* - /* To avoid change filament for non-used extruder for Multi-material, - * check print.model().custom_gcode_per_print_z using tool_ordering values - * / - if (!m_custom_gcode_per_print_z. empty()) - { - bool delete_executed = false; - auto it = m_custom_gcode_per_print_z.end(); - while (it != m_custom_gcode_per_print_z.begin()) - { - --it; - if (it->gcode != ColorChangeCode) - continue; - - auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->print_z)); - - bool used_extruder = false; - for (; it_layer_tools != tool_ordering.end(); it_layer_tools++) - { - const std::vector& extruders = it_layer_tools->extruders; - if (std::find(extruders.begin(), extruders.end(), (unsigned)(it->extruder-1)) != extruders.end()) - { - used_extruder = true; - break; - } - } - if (used_extruder) - continue; - - /* If we are there, current extruder wouldn't be used, - * so this color change is a redundant move. - * Delete this item from m_custom_gcode_per_print_z - * / - it = m_custom_gcode_per_print_z.erase(it); - delete_executed = true; - } - - if (delete_executed) - print.model().custom_gcode_per_print_z = m_custom_gcode_per_print_z; - } -*/ - m_cooling_buffer->set_current_extruder(initial_extruder_id); // Emit machine envelope limits for the Marlin firmware. @@ -1779,62 +1730,39 @@ namespace ProcessLayer { std::string emit_custom_gcode_per_print_z( - // Last processed CustomGCode. - std::vector::const_iterator &custom_gcode_per_print_z_it, - const std::vector::const_iterator custom_gcode_per_print_z_end, - // This layer's print_z. - coordf_t current_print_z, + const Model::CustomGCode *custom_gcode, // ID of the first extruder printing this layer. unsigned int first_extruder_id, - size_t num_extruders) + bool single_material_print) { - // Let's issue a filament change command if requested at this layer. - // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. - // (Layers can be close to each other, model could have been resliced with bigger layer height, ...). - bool has_colorchange = false; + std::string gcode; + + if (custom_gcode != nullptr) { + // Extruder switches are processed by LayerTools, they should be filtered out. + assert(custom_gcode->gcode != ExtruderChangeCode); - std::string custom_code; - std::string pause_print_msg; - int m600_before_extruder = -1; - while (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end) { - auto it_next = custom_gcode_per_print_z_it; - if ((++ it_next)->print_z >= current_print_z + EPSILON) - break; - custom_gcode_per_print_z_it = it_next; - } - if (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end && custom_gcode_per_print_z_it->print_z < current_print_z + EPSILON) { - custom_code = custom_gcode_per_print_z_it->gcode; + const std::string &custom_code = custom_gcode->gcode; + std::string pause_print_msg; + int m600_extruder_before_layer = -1; + if (custom_code == ColorChangeCode && custom_gcode->extruder > 0) + m600_extruder_before_layer = custom_gcode->extruder - 1; + else if (custom_code == PausePrintCode) + pause_print_msg = custom_gcode->color; - if (custom_code == ColorChangeCode && custom_gcode_per_print_z_it->extruder > 0) - m600_before_extruder = custom_gcode_per_print_z_it->extruder - 1; - if (custom_code == PausePrintCode) - pause_print_msg = custom_gcode_per_print_z_it->color; - - // This color change is consumed, don't use it again. - ++ custom_gcode_per_print_z_it; - has_colorchange = true; - } - - // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count - - // don't save "tool_change"(ExtruderChangeCode) code to GCode - std::string gcode; - if (has_colorchange && custom_code != ExtruderChangeCode) { - const bool single_material_print = num_extruders == 1; - + // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count if (custom_code == ColorChangeCode) // color change { // add tag for analyzer - gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n"; + gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; // add tag for time estimator gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; - if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder + if (!single_material_print && m600_extruder_before_layer >= 0 && first_extruder_id != m600_extruder_before_layer // && !MMU1 ) { //! FIXME_in_fw show message during print pause gcode += "M601\n"; // pause print - gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n"; + gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n"; } else gcode += custom_code + "\n"; @@ -1860,7 +1788,7 @@ namespace ProcessLayer } gcode += custom_code + "\n"; } - } + } return gcode; } @@ -2048,11 +1976,7 @@ void GCode::process_layer( if (single_object_instance_idx == size_t(-1) && object_layer != nullptr) { // Normal (non-sequential) print. - gcode += ProcessLayer::emit_custom_gcode_per_print_z( - // input / output - m_custom_gcode_per_print_z_it, - // inputs - print.model().custom_gcode_per_print_z.cend(), layer.print_z, first_extruder_id, print.config().nozzle_diameter.size()); + gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config().nozzle_diameter.size() == 1); // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. skirt_loops_per_extruder = first_layer ? diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 10644a60b..aee8ee2e2 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -374,9 +374,6 @@ private: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; - // Iterator to Model::custom_gcode_per_print_z, which is being increased by process_layer. - // The Model::custom_gcode_per_print_z may contain color changes, extruder switches, pauses and custom G-codes. - std::vector::const_iterator m_custom_gcode_per_print_z_it; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index c70abbbbd..26e125bbc 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -956,7 +956,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ GCodePreviewData::Extrusion::Path &path = paths.back(); path.polyline = polyline; path.extrusion_role = data.extrusion_role; - path.mm3_per_mm = data.mm3_per_mm; + path.mm3_per_mm = float(data.mm3_per_mm); path.width = data.width; path.height = data.height; path.feedrate = data.feedrate; diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index b00bc73eb..6815ea73a 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -303,8 +303,8 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: unsigned int extruder_id = extruders[i].id(); adj.extruder_id = extruder_id; adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id); - adj.slowdown_below_layer_time = config.slowdown_below_layer_time.get_at(extruder_id); - adj.min_print_speed = config.min_print_speed.get_at(extruder_id); + adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id)); + adj.min_print_speed = float(config.min_print_speed.get_at(extruder_id)); map_extruder_to_per_extruder_adjustment[extruder_id] = i; } diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index d44ef1aad..1fedcf3f0 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -29,7 +29,7 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusion_path) { - BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)); + BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width))); BoundingBoxf bboxf; if (! empty(bbox)) { bboxf.min = unscale(bbox.min); @@ -43,7 +43,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio { BoundingBox bbox; for (const ExtrusionPath &extrusion_path : extrusion_loop.paths) - bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width))); + bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width)))); BoundingBoxf bboxf; if (! empty(bbox)) { bboxf.min = unscale(bbox.min); @@ -57,7 +57,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext { BoundingBox bbox; for (const ExtrusionPath &extrusion_path : extrusion_multi_path.paths) - bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width))); + bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width)))); BoundingBoxf bboxf; if (! empty(bbox)) { bboxf.min = unscale(bbox.min); diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 3edb7cf17..c2febbafb 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -15,6 +15,8 @@ #include +#include "../GCodeWriter.hpp" + namespace Slic3r { @@ -99,7 +101,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // For the use case when all objects are printed at once. // (print.config().complete_objects is false). -ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material, const std::vector> *per_layer_extruder_switches) +ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { m_print_config_ptr = &print.config(); @@ -124,9 +126,16 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->initialize_layers(zs); } + // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. + // Do it only if all the objects were configured to be printed with a single extruder. + const std::vector> *per_layer_extruder_switches = (print.object_extruders().size() == 1) ? + &custom_tool_changes(print.model(), (unsigned int)print.config().nozzle_diameter.size()) : nullptr; + if (per_layer_extruder_switches != nullptr && per_layer_extruder_switches->empty()) + per_layer_extruder_switches = nullptr; + // Collect extruders reuqired to print the layers. for (auto object : print.objects()) - this->collect_extruders(*object, (per_layer_extruder_switches != nullptr && ! per_layer_extruder_switches->empty()) ? per_layer_extruder_switches : nullptr); + this->collect_extruders(*object, per_layer_extruder_switches); // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); @@ -134,6 +143,11 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->fill_wipe_tower_partitions(print.config(), object_bottom_z); this->collect_extruder_statistics(prime_multi_material); + + // Assign custom G-code actions from Model::custom_gcode_per_print_z to their respecive layers, + // ignoring the extruder switches, which were processed above, and ignoring color changes for extruders, + // that do not print above their respective print_z. + this->assign_custom_gcodes(print); } void ToolOrdering::initialize_layers(std::vector &zs) @@ -444,6 +458,46 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) } } +// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools. +// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer. +// If multiple events are planned over a span of a single layer, use the last one. +void ToolOrdering::assign_custom_gcodes(const Print &print) +{ + const std::vector &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; + if (custom_gcode_per_print_z.empty()) + return; + + unsigned int num_extruders = *std::max_element(m_all_printing_extruders.begin(), m_all_printing_extruders.end()) + 1; + std::vector extruder_printing_above(num_extruders, false); + auto custom_gcode_it = custom_gcode_per_print_z.rbegin(); + // From the last layer to the first one: + for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) { + LayerTools < = *it_lt; + // Add the extruders of the current layer to the set of extruders printing at and above this print_z. + for (unsigned int i : lt.extruders) + extruder_printing_above[i] = true; + // Skip all custom G-codes above this layer and skip all extruder switches. + for (; custom_gcode_it != custom_gcode_per_print_z.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ExtruderChangeCode); ++ custom_gcode_it); + if (custom_gcode_it == custom_gcode_per_print_z.rend()) + // Custom G-codes were processed. + break; + // Some custom G-code is configured for this layer or a layer below. + const Model::CustomGCode &custom_gcode = *custom_gcode_it; + // print_z of the layer below the current layer. + coordf_t print_z_below = 0.; + if (auto it_lt_below = it_lt; -- it_lt_below != m_layer_tools.rend()) + print_z_below = it_lt_below->print_z; + if (custom_gcode.print_z > print_z_below - EPSILON) { + // The custom G-code applies to the current layer. + if (custom_gcode.gcode != ColorChangeCode || extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) + // If it is color change, it will actually be useful as the exturder above will print. + lt.custom_gcode = &custom_gcode; + // Consume that custom G-code event. + -- custom_gcode_it; + } + } +} + const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const { auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 1f043d94f..54024fc72 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -80,14 +80,7 @@ private: class LayerTools { public: - LayerTools(const coordf_t z) : - print_z(z), - has_object(false), - has_support(false), - extruder_override(0), - has_wipe_tower(false), - wipe_tower_partitions(0), - wipe_tower_layer_height(0.) {} + LayerTools(const coordf_t z) : print_z(z) {} // Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other. // In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports). @@ -104,22 +97,24 @@ public: // Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden. unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const; - coordf_t print_z; - bool has_object; - bool has_support; + coordf_t print_z = 0.; + bool has_object = false; + bool has_support = false; // Zero based extruder IDs, ordered to minimize tool switches. std::vector extruders; // If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with. // If not overriden, it is set to 0. - unsigned int extruder_override; + unsigned int extruder_override = 0; // Will there be anything extruded on this layer for the wipe tower? // Due to the support layers possibly interleaving the object layers, // wipe tower will be disabled for some support only layers. - bool has_wipe_tower; + bool has_wipe_tower = false; // Number of wipe tower partitions to support the required number of tool switches // and to support the wipe tower partitions above this one. - size_t wipe_tower_partitions; - coordf_t wipe_tower_layer_height; + size_t wipe_tower_partitions = 0; + coordf_t wipe_tower_layer_height = 0.; + // Custom G-code (color change, extruder switch, pause) to be performed before this layer starts to print. + const Model::CustomGCode *custom_gcode = nullptr; WipingExtrusions& wiping_extrusions() { m_wiping_extrusions.set_layer_tools_ptr(this); @@ -144,7 +139,7 @@ public: // For the use case when all objects are printed at once. // (print.config.complete_objects is false). - ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false, const std::vector> *per_layer_extruder_switches = nullptr); + ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false); void clear() { m_layer_tools.clear(); } @@ -175,6 +170,7 @@ private: void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); + void assign_custom_gcodes(const Print &print); std::vector m_layer_tools; // First printing extruder, including the multi-material priming sequence. @@ -184,7 +180,6 @@ private: // All extruders, which extrude some material over m_layer_tools. std::vector m_all_printing_extruders; - const PrintConfig* m_print_config_ptr = nullptr; }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 2d327c70b..ed8817882 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1912,8 +1912,8 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt, double first_l // If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default. if (! is_step_done(psWipeTower) && extruders_cnt !=0) { - float width = m_config.wipe_tower_width; - float brim_spacing = nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4); + float width = float(m_config.wipe_tower_width); + float brim_spacing = float(nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4)); const_cast(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1); const_cast(this)->m_wipe_tower_data.brim_width = 4.5f * brim_spacing; @@ -1938,8 +1938,7 @@ void Print::_make_wipe_tower() wipe_volumes.push_back(std::vector(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. - m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true, - (this->object_extruders().size() == 1) ? &custom_tool_changes(this->model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr); + m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); if (! m_wipe_tower_data.tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. From c96fc5eb513c2f09ac561cb8893bad72b2692a50 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 12:10:01 +0100 Subject: [PATCH 41/85] gcc & clang do not like taking reference of const temporaries. --- src/libslic3r/GCode/ToolOrdering.cpp | 19 ++++++++----------- src/libslic3r/GCode/ToolOrdering.hpp | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index c2febbafb..628379aaf 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -89,7 +89,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude } // Collect extruders reuqired to print the layers. - this->collect_extruders(object, nullptr); + this->collect_extruders(object, std::vector>()); // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); @@ -128,10 +128,9 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. // Do it only if all the objects were configured to be printed with a single extruder. - const std::vector> *per_layer_extruder_switches = (print.object_extruders().size() == 1) ? - &custom_tool_changes(print.model(), (unsigned int)print.config().nozzle_diameter.size()) : nullptr; - if (per_layer_extruder_switches != nullptr && per_layer_extruder_switches->empty()) - per_layer_extruder_switches = nullptr; + std::vector> per_layer_extruder_switches; + if (print.object_extruders().size() == 1) + per_layer_extruder_switches = custom_tool_changes(print.model(), (unsigned int)print.config().nozzle_diameter.size()); // Collect extruders reuqired to print the layers. for (auto object : print.objects()) @@ -166,7 +165,7 @@ void ToolOrdering::initialize_layers(std::vector &zs) } // Collect extruders reuqired to print layers. -void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector> *per_layer_extruder_switches) +void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector> &per_layer_extruder_switches) { // Collect the support extruders. for (auto support_layer : object.support_layers()) { @@ -186,8 +185,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto // Extruder overrides are ordered by print_z. std::vector>::const_iterator it_per_layer_extruder_override; - if (per_layer_extruder_switches != nullptr) - it_per_layer_extruder_override = per_layer_extruder_switches->begin(); + it_per_layer_extruder_override = per_layer_extruder_switches.begin(); unsigned int extruder_override = 0; // Collect the object extruders. @@ -195,9 +193,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto LayerTools &layer_tools = this->tools_for_layer(layer->print_z); // Override extruder with the next - if (per_layer_extruder_switches != nullptr) - for (; it_per_layer_extruder_override != per_layer_extruder_switches->end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override) - extruder_override = (int)it_per_layer_extruder_override->second; + for (; it_per_layer_extruder_override != per_layer_extruder_switches.end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override) + extruder_override = (int)it_per_layer_extruder_override->second; // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it. layer_tools.extruder_override = extruder_override; diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 54024fc72..a9d5a98e7 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -166,7 +166,7 @@ public: private: void initialize_layers(std::vector &zs); - void collect_extruders(const PrintObject &object, const std::vector> *per_layer_extruder_switches); + void collect_extruders(const PrintObject &object, const std::vector> &per_layer_extruder_switches); void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); From b54ce0d468d0d842861f93f875c42d26cbc16f92 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 14:24:38 +0100 Subject: [PATCH 42/85] Fixing GCode Skirt generator after refactoring. --- src/libslic3r/GCode.cpp | 36 +++++++++++++++++------------------- src/libslic3r/GCode.hpp | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 6fa145bf6..c42c1c35a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1800,14 +1800,13 @@ namespace Skirt { const std::vector &layers, const LayerTools &layer_tools, std::vector extruder_ids, - // Heights at which the skirt has already been extruded. - std::vector &skirt_done) + // Heights (print_z) at which the skirt has already been extruded. + std::vector &skirt_done) { // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. std::map> skirt_loops_per_extruder_out; - assert(skirt_done.empty()); - if (print.has_skirt() && ! print.skirt().entities.empty()) { + if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) { // Prime all the printing extruders over the skirt lines. // Reorder the extruders, so that the last used extruder is at the front. unsigned int first_extruder_id = layer_tools.extruders.front(); @@ -1835,7 +1834,7 @@ namespace Skirt { (i == 0) ? 0 : extruder_loops[i - 1], ((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]); } - skirt_done.emplace_back(layer_tools.print_z - (skirt_done.empty() ? 0. : skirt_done.back())); + skirt_done.emplace_back(layer_tools.print_z); } return skirt_loops_per_extruder_out; @@ -1845,8 +1844,8 @@ namespace Skirt { const Print &print, const std::vector &layers, const LayerTools &layer_tools, - // Heights at which the skirt has already been extruded. - std::vector &skirt_done) + // Heights (print_z) at which the skirt has already been extruded. + std::vector &skirt_done) { // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. @@ -1855,16 +1854,15 @@ namespace Skirt { // Not enough skirt layers printed yet. //FIXME infinite or high skirt does not make sense for sequential print! (skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) && - // This print_z has not been extruded yet + // This print_z has not been extruded yet (sequential print) skirt_done.back() < layer_tools.print_z - EPSILON && // and this layer is an object layer, or it is a raft layer. - //FIXME one uses the number of raft layers from the 1st object! (layer_tools.has_object || layers.front().support_layer->id() < (size_t)layers.front().support_layer->object()->config().raft_layers.value)) { // Extrude all skirts with the current extruder. unsigned int first_extruder_id = layer_tools.extruders.front(); skirt_loops_per_extruder_out[first_extruder_id] = std::pair(0, print.config().skirts.value); assert(!skirt_done.empty()); - skirt_done.emplace_back(layer_tools.print_z - skirt_done.back()); + skirt_done.emplace_back(layer_tools.print_z); } return skirt_loops_per_extruder_out; } @@ -1974,15 +1972,15 @@ void GCode::process_layer( // Map from extruder ID to index of skirt loops to be extruded with that extruder. std::map> skirt_loops_per_extruder; - if (single_object_instance_idx == size_t(-1) && object_layer != nullptr) { - // Normal (non-sequential) print. - gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config().nozzle_diameter.size() == 1); - // Extrude skirt at the print_z of the raft layers and normal object layers - // not at the print_z of the interlaced support material layers. - skirt_loops_per_extruder = first_layer ? - Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_writer.extruder_ids(), m_skirt_done) : - Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done); + if (single_object_instance_idx == size_t(-1)) { + // Normal (non-sequential) print. + gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config().nozzle_diameter.size() == 1); } + // Extrude skirt at the print_z of the raft layers and normal object layers + // not at the print_z of the interlaced support material layers. + skirt_loops_per_extruder = first_layer ? + Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_writer.extruder_ids(), m_skirt_done) : + Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done); // Group extrusions by an extruder, then by an object, an island and a region. std::map> by_extruder; @@ -2157,7 +2155,7 @@ void GCode::process_layer( this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp = true; Flow layer_skirt_flow(print.skirt_flow()); - layer_skirt_flow.height = (float)(m_skirt_done.back() - ((m_skirt_done.size() == 1) ? 0. : m_skirt_done[m_skirt_done.size() - 2])); + layer_skirt_flow.height = float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])); double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); for (size_t i = loops.first; i < loops.second; ++i) { // Adjust flow according to this layer's layer height. diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index aee8ee2e2..0344924a1 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -366,7 +366,7 @@ private: #endif /* HAS_PRESSURE_EQUALIZER */ std::unique_ptr m_wipe_tower; - // Heights at which the skirt has already been extruded. + // Heights (print_z) at which the skirt has already been extruded. std::vector m_skirt_done; // Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print. bool m_brim_done; From ab6a2b71e8d40df4956626d758063f956229e218 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 15:12:45 +0100 Subject: [PATCH 43/85] Another bugfixes of GCode export after refactoring. --- src/libslic3r/GCode/ToolOrdering.cpp | 5 ++--- src/libslic3r/GCodeWriter.cpp | 3 ++- src/libslic3r/GCodeWriter.hpp | 2 +- src/libslic3r/Print.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 628379aaf..0b8fa1132 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -570,9 +570,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int const LayerTools& lt = *m_layer_tools; const float min_infill_volume = 0.f; // ignore infill with smaller volume than this - assert(volume_to_wipe >= 0.); - if (! this->something_overridable || volume_to_wipe == 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) - return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it + if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) + return 0.f; // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: PrintObjectPtrs object_list = print.objects(); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 0266eee39..4c53048dc 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -23,8 +23,9 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) print_config.machine_max_acceleration_extruding.values.front() : 0); } -void GCodeWriter::set_extruders(const std::vector &extruder_ids) +void GCodeWriter::set_extruders(std::vector extruder_ids) { + std::sort(extruder_ids.begin(), extruder_ids.end()); m_extruders.clear(); m_extruders.reserve(extruder_ids.size()); for (unsigned int extruder_id : extruder_ids) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 1631d8590..667c1ef95 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -33,7 +33,7 @@ public: std::string extrusion_axis() const { return m_extrusion_axis; } void apply_print_config(const PrintConfig &print_config); // Extruders are expected to be sorted in an increasing order. - void set_extruders(const std::vector &extruder_ids); + void set_extruders(std::vector extruder_ids); const std::vector& extruders() const { return m_extruders; } std::vector extruder_ids() const { std::vector out; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 89d27e3cb..42f8d761e 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -52,7 +52,7 @@ public: // Average diameter of nozzles participating on extruding this region. coordf_t bridging_height_avg(const PrintConfig &print_config) const; - // Collect extruder indices used to print this region's object. + // Collect 0-based extruder indices used to print this region's object. void collect_object_printing_extruders(std::vector &object_extruders) const; static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders); From fd6c9582d52f05abdd9851ff02894bfc8127c2ef Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 14 Jan 2020 15:43:43 +0100 Subject: [PATCH 44/85] Refactoring fix: making sure that mark_wiping_extrusions doesn't report it wiped something it didn't --- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 0b8fa1132..d937d4eed 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -571,7 +571,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int const float min_infill_volume = 0.f; // ignore infill with smaller volume than this if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) - return 0.f; // Soluble filament cannot be wiped in a random infill, neither the filament after it + return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: PrintObjectPtrs object_list = print.objects(); From 390376daae8a60b7fb7bf856c83865eb04e23c2e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 16:10:53 +0100 Subject: [PATCH 45/85] Fix of recent refactoring of color print. --- src/libslic3r/GCode/ToolOrdering.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index d937d4eed..4374d5be0 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -482,7 +482,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) const Model::CustomGCode &custom_gcode = *custom_gcode_it; // print_z of the layer below the current layer. coordf_t print_z_below = 0.; - if (auto it_lt_below = it_lt; -- it_lt_below != m_layer_tools.rend()) + if (auto it_lt_below = it_lt; ++ it_lt_below != m_layer_tools.rend()) print_z_below = it_lt_below->print_z; if (custom_gcode.print_z > print_z_below - EPSILON) { // The custom G-code applies to the current layer. @@ -490,7 +490,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) // If it is color change, it will actually be useful as the exturder above will print. lt.custom_gcode = &custom_gcode; // Consume that custom G-code event. - -- custom_gcode_it; + ++ custom_gcode_it; } } } From 10d1b459bb305683a6c919ced40f98d1d6553928 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 16:38:34 +0100 Subject: [PATCH 46/85] Fix of Skirt loops not being honored, only producing single loop #2193 First layer skirt only has half the loops when using multiple extruders #469 The skirt generator used to prime all printing extruders at the 1st layer if enough skirt lines were configured, while at the other layers the skirt used to be printed with the 1st extruder printing the layer. There was a bug introduced quite a long time ago, where not enough skirt lines were extruded if some extruders were not needed to print the 1st layer. Newly the skirt generator works the same way on all layers: All the extruders planned to print a layer are primed over the skirt if enough skirt lines are configured. --- src/libslic3r/GCode.cpp | 61 ++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c42c1c35a..870749867 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1729,7 +1729,7 @@ std::vector GCode::sort_print_object_instances( namespace ProcessLayer { - std::string emit_custom_gcode_per_print_z( + static std::string emit_custom_gcode_per_print_z( const Model::CustomGCode *custom_gcode, // ID of the first extruder printing this layer. unsigned int first_extruder_id, @@ -1795,11 +1795,20 @@ namespace ProcessLayer } // namespace ProcessLayer namespace Skirt { - std::map> make_skirt_loops_per_extruder_1st_layer( + static void skirt_loops_per_extruder_all_printing(const Print &print, const LayerTools &layer_tools, std::map> &skirt_loops_per_extruder_out) + { + // Prime all extruders printing over the 1st layer over the skirt lines. + size_t n_loops = print.skirt().entities.size(); + size_t n_tools = layer_tools.extruders.size(); + size_t lines_per_extruder = (n_loops + n_tools - 1) / n_tools; + for (size_t i = 0; i < n_loops; i += lines_per_extruder) + skirt_loops_per_extruder_out[layer_tools.extruders[i / lines_per_extruder]] = std::pair(i, std::min(i + lines_per_extruder, n_loops)); + } + + static std::map> make_skirt_loops_per_extruder_1st_layer( const Print &print, - const std::vector &layers, + const std::vector & /*layers */, const LayerTools &layer_tools, - std::vector extruder_ids, // Heights (print_z) at which the skirt has already been extruded. std::vector &skirt_done) { @@ -1807,40 +1816,13 @@ namespace Skirt { // not at the print_z of the interlaced support material layers. std::map> skirt_loops_per_extruder_out; if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) { - // Prime all the printing extruders over the skirt lines. - // Reorder the extruders, so that the last used extruder is at the front. - unsigned int first_extruder_id = layer_tools.extruders.front(); - for (size_t i = 1; i < extruder_ids.size(); ++ i) - if (extruder_ids[i] == first_extruder_id) { - // Move the last extruder to the front. - memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int)); - extruder_ids.front() = first_extruder_id; - break; - } - size_t n_loops = print.skirt().entities.size(); - if (n_loops <= extruder_ids.size()) { - for (size_t i = 0; i < n_loops; ++i) - skirt_loops_per_extruder_out[extruder_ids[i]] = std::pair(i, i + 1); - } else { - // Assign skirt loops to the extruders. - std::vector extruder_loops(extruder_ids.size(), 1); - n_loops -= extruder_loops.size(); - while (n_loops > 0) { - for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++i, --n_loops) - ++extruder_loops[i]; - } - for (size_t i = 0; i < extruder_ids.size(); ++i) - skirt_loops_per_extruder_out[extruder_ids[i]] = std::make_pair( - (i == 0) ? 0 : extruder_loops[i - 1], - ((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]); - } + skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); skirt_done.emplace_back(layer_tools.print_z); - } return skirt_loops_per_extruder_out; } - std::map> make_skirt_loops_per_extruder_other_layers( + static std::map> make_skirt_loops_per_extruder_other_layers( const Print &print, const std::vector &layers, const LayerTools &layer_tools, @@ -1858,9 +1840,14 @@ namespace Skirt { skirt_done.back() < layer_tools.print_z - EPSILON && // and this layer is an object layer, or it is a raft layer. (layer_tools.has_object || layers.front().support_layer->id() < (size_t)layers.front().support_layer->object()->config().raft_layers.value)) { - // Extrude all skirts with the current extruder. - unsigned int first_extruder_id = layer_tools.extruders.front(); - skirt_loops_per_extruder_out[first_extruder_id] = std::pair(0, print.config().skirts.value); +#if 0 + // Prime just the first printing extruder. This is original Slic3r's implementation. + skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirts.value); +#else + // Prime all extruders planned for this layer, see + // https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619 + skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); +#endif assert(!skirt_done.empty()); skirt_done.emplace_back(layer_tools.print_z); } @@ -1979,7 +1966,7 @@ void GCode::process_layer( // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. skirt_loops_per_extruder = first_layer ? - Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_writer.extruder_ids(), m_skirt_done) : + Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_skirt_done) : Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done); // Group extrusions by an extruder, then by an object, an island and a region. From 2c958c021dfec353fe598d3c818e83edadceb7d4 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 14 Jan 2020 17:35:42 +0100 Subject: [PATCH 47/85] Fixed regression in placement of Color Change event at the correct layer. --- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 4374d5be0..a76f0fafb 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -484,7 +484,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) coordf_t print_z_below = 0.; if (auto it_lt_below = it_lt; ++ it_lt_below != m_layer_tools.rend()) print_z_below = it_lt_below->print_z; - if (custom_gcode.print_z > print_z_below - EPSILON) { + if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) { // The custom G-code applies to the current layer. if (custom_gcode.gcode != ColorChangeCode || extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) // If it is color change, it will actually be useful as the exturder above will print. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 9d6a2a5ec..8af721f9d 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -95,14 +95,6 @@ void BackgroundSlicingProcess::process_fff() m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR - /* #ys_FIXME_no_exported_codes - if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) { - GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z; - GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n" - "Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info"))); - } - */ - if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { //FIXME localize the messages From 536514ff03fadec4fa92776f3fb81e0e9cec17ef Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 15 Jan 2020 09:33:19 +0100 Subject: [PATCH 48/85] Added default filament(resin) in wizard for selected printers Added default_materials field to "Vendor".ini --- resources/profiles/Creality.ini | 1 + resources/profiles/PrusaResearch.ini | 12 +++ src/slic3r/GUI/ConfigWizard.cpp | 106 +++++++++++++++++++++++- src/slic3r/GUI/ConfigWizard_private.hpp | 13 ++- 4 files changed, 128 insertions(+), 4 deletions(-) diff --git a/resources/profiles/Creality.ini b/resources/profiles/Creality.ini index 4ebf99d32..eba85fef1 100644 --- a/resources/profiles/Creality.ini +++ b/resources/profiles/Creality.ini @@ -18,6 +18,7 @@ config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/Prusa name = Creality Ender-3 variants = 0.4 technology = FFF +default_materials = Creality PLA @ENDER3; Prusament PLA @ENDER3 # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 746aaf966..a2dfc4913 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -22,72 +22,84 @@ name = Original Prusa MINI variants = 0.4; 0.25; 0.6 technology = FFF family = MINI +default_materials = Prusament PLA; Prusament PETG @MINI [printer_model:MK3S] name = Original Prusa i3 MK3S variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +default_materials = Prusament PLA; Prusament PETG [printer_model:MK3] name = Original Prusa i3 MK3 variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +default_materials = Prusament PLA; Prusament PETG [printer_model:MK3SMMU2S] name = Original Prusa i3 MK3S MMU2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2 [printer_model:MK3MMU2] name = Original Prusa i3 MK3 MMU2 variants = 0.4; 0.25; 0.6 technology = FFF family = MK3 +default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2 [printer_model:MK2.5S] name = Original Prusa i3 MK2.5S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +default_materials = Prusament PLA; Prusament PETG [printer_model:MK2.5] name = Original Prusa i3 MK2.5 variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +default_materials = Prusament PLA; Prusament PETG [printer_model:MK2.5SMMU2S] name = Original Prusa i3 MK2.5S MMU2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2 [printer_model:MK2.5MMU2] name = Original Prusa i3 MK2.5 MMU2 variants = 0.4; 0.25; 0.6 technology = FFF family = MK2.5 +default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2 [printer_model:MK2S] name = Original Prusa i3 MK2S variants = 0.4; 0.25; 0.6 technology = FFF family = MK2 +default_materials = Prusament PLA; Prusament PETG [printer_model:MK2SMM] name = Original Prusa i3 MK2S MMU1 variants = 0.4; 0.6 technology = FFF family = MK2 +default_materials = Prusament PLA; Prusament PETG @MMU1 [printer_model:SL1] name = Original Prusa SL1 variants = default technology = SLA family = SL1 +default_materials = Prusa Transparent Tough @0.05 # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 8a4b28d3a..add680a40 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -350,6 +350,21 @@ bool PrinterPicker::any_selected() const return false; } +std::set PrinterPicker::get_selected_models() const +{ + std::set ret_set; + + for (const auto& cb : cboxes) + if (cb->GetValue()) + ret_set.emplace(cb->model); + + for (const auto& cb : cboxes_alt) + if (cb->GetValue()) + ret_set.emplace(cb->model); + + return ret_set; +} + void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked) { PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked); @@ -500,6 +515,19 @@ bool PagePrinters::any_selected() const return false; } +std::set PagePrinters::get_selected_models() +{ + std::set ret_set; + + for (const auto *picker : printer_pickers) + { + std::set tmp_models = picker->get_selected_models(); + ret_set.insert(tmp_models.begin(), tmp_models.end()); + } + + return ret_set; +} + void PagePrinters::set_run_reason(ConfigWizard::RunReason run_reason) { if (technology == T_FFF @@ -1600,6 +1628,10 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker preset.is_visible = evt.enable; } } + + // if at list one printer is selected but there in no one selected material, + // select materials which is default for selected printer(s) + select_default_materials_if_needed(pair.second.vendor_profile, page->technology, evt.model_id); } if (page->technology & T_FFF) { @@ -1609,6 +1641,57 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker } } +void ConfigWizard::priv::select_default_materials_for_printer_model(const std::vector& models, Technology technology, const std::string& model_id) +{ + PageMaterials* page_materials = technology & T_FFF ? page_filaments : page_sla_materials; + + auto it = std::find_if(models.begin(), models.end(), [model_id](VendorProfile::PrinterModel model) {return model_id == model.id; }); + if (it != models.end()) + for (const std::string& material : it->default_materials) + appconfig_new.set(page_materials->materials->appconfig_section(), material, "1"); +} + +void ConfigWizard::priv::select_default_materials_if_needed(VendorProfile* vendor_profile, Technology technology, const std::string& model_id) +{ + if ((technology & T_FFF && !any_fff_selected) || + (technology & T_SLA && !any_sla_selected) || + check_materials_in_config(technology, false)) + return; + + select_default_materials_for_printer_model(vendor_profile->models, technology, model_id); +} + +void ConfigWizard::priv::selected_default_materials(Technology technology) +{ + auto select_default_materials_for_printer_page = [this](PagePrinters * page_printers, Technology technology) + { + std::set selected_models = page_printers->get_selected_models(); + const std::string vendor_id = page_printers->get_vendor_id(); + + for (auto& pair : bundles) + { + if (pair.first != vendor_id) + continue; + + for (const std::string& model_id : selected_models) + select_default_materials_for_printer_model(pair.second.vendor_profile->models, technology, model_id); + } + }; + + PagePrinters* page_printers = technology & T_FFF ? page_fff : page_msla; + select_default_materials_for_printer_page(page_printers, technology); + + for (const auto& printer : pages_3rdparty) + { + page_printers = technology & T_FFF ? printer.second.first : printer.second.second; + if (page_printers) + select_default_materials_for_printer_page(page_printers, technology); + } + + update_materials(technology); + (technology& T_FFF ? page_filaments : page_sla_materials)->reload_presets(); +} + void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install) { auto it = pages_3rdparty.find(vendor->id); @@ -1645,7 +1728,7 @@ bool ConfigWizard::priv::on_bnt_finish() return check_materials_in_config(T_ANY); } -bool ConfigWizard::priv::check_materials_in_config(Technology technology) +bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool show_info_msg) { const auto exist_preset = [this](const std::string& section, const Materials& materials) { @@ -1660,15 +1743,32 @@ bool ConfigWizard::priv::check_materials_in_config(Technology technology) return false; }; + const auto ask_and_selected_default_materials = [this](wxString message, Technology technology) + { + wxMessageDialog msg(q, message, _(L("Notice")), wxYES_NO); + if (msg.ShowModal() == wxID_YES) + selected_default_materials(technology); + }; + if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments)) { - show_info(q, _(L("You have to select at least one filament for selected printers")), ""); + if (show_info_msg) + { + wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" + + _(L("Do you want to automatic select default filaments?")); + ask_and_selected_default_materials(message, T_FFF); + } return false; } if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials)) { - show_info(q, _(L("You have to select at least one material for selected printers")), ""); + if (show_info_msg) + { + wxString message = _(L("You have to select at least one material for selected printers")) + "\n\n\t" + + _(L("Do you want to automatic select default materials?")); + ask_and_selected_default_materials(message, T_SLA); + } return false; } diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 3ea5321f8..9c14633c9 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -149,6 +149,7 @@ struct PrinterPicker: wxPanel void select_all(bool select, bool alternates = false); void select_one(size_t i, bool select); bool any_selected() const; + std::set get_selected_models() const ; int get_width() const { return width; } const std::vector& get_button_indexes() { return m_button_indexes; } @@ -215,6 +216,9 @@ struct PagePrinters: ConfigWizardPage void select_all(bool select, bool alternates = false); int get_width() const; bool any_selected() const; + std::set get_selected_models(); + + std::string get_vendor_id() const { return printer_pickers.empty() ? "" : printer_pickers[0]->vendor_id; } virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; }; @@ -503,10 +507,17 @@ struct ConfigWizard::priv void on_custom_setup(); void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); + void select_default_materials_for_printer_model(const std::vector &models, + Technology technology, + const std::string & model_id); + void select_default_materials_if_needed(VendorProfile* vendor_profile, + Technology technology, + const std::string &model_id); + void selected_default_materials(Technology technology); void on_3rdparty_install(const VendorProfile *vendor, bool install); bool on_bnt_finish(); - bool check_materials_in_config(Technology technology); + bool check_materials_in_config(Technology technology, bool show_info_msg = true); void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); // #ys_FIXME_alise void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add); From 62e60bcb43dcf147596b5ae466afb6c04e6bcb2a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 15 Jan 2020 12:49:34 +0100 Subject: [PATCH 49/85] Six degrees of freedom camera - 1st installment --- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/3DBed.cpp | 14 +++ src/slic3r/GUI/3DBed.hpp | 4 + src/slic3r/GUI/Camera.cpp | 144 ++++++++++++++++++++++++++- src/slic3r/GUI/Camera.hpp | 37 ++++++- src/slic3r/GUI/GLCanvas3D.cpp | 31 ++++++ src/slic3r/GUI/Mouse3DController.cpp | 11 ++ src/slic3r/GUI/Selection.cpp | 4 + 8 files changed, 245 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 23c516a34..401946b94 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -74,5 +74,7 @@ // Enable configurable paths export (fullpath or not) to 3mf and amf #define ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF (1 && ENABLE_2_2_0_BETA1) +// Enable 6 degrees of freedom camera +#define ENABLE_6DOF_CAMERA (1 && ENABLE_2_2_0_BETA1) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c66c8efdd..698dbbc05 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -262,7 +262,11 @@ Point Bed3D::point_projection(const Point& point) const return m_polygon.point_projection(point); } +#if ENABLE_6DOF_CAMERA +void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const +#else void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const +#endif // ENABLE_6DOF_CAMERA { m_scale_factor = scale_factor; @@ -273,6 +277,15 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho switch (m_type) { +#if ENABLE_6DOF_CAMERA + case MK2: { render_prusa(canvas, "mk2", bottom); break; } + case MK3: { render_prusa(canvas, "mk3", bottom); break; } + case SL1: { render_prusa(canvas, "sl1", bottom); break; } + case MINI: { render_prusa(canvas, "mini", bottom); break; } + case ENDER3: { render_prusa(canvas, "ender3", bottom); break; } + default: + case Custom: { render_custom(canvas, bottom); break; } +#else case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; } case MK3: { render_prusa(canvas, "mk3", theta > 90.0f); break; } case SL1: { render_prusa(canvas, "sl1", theta > 90.0f); break; } @@ -280,6 +293,7 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho case ENDER3: { render_prusa(canvas, "ender3", theta > 90.0f); break; } default: case Custom: { render_custom(canvas, theta > 90.0f); break; } +#endif // ENABLE_6DOF_CAMERA } glsafe(::glDisable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index cd2de862e..c1d3fdce7 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -110,7 +110,11 @@ public: bool contains(const Point& point) const; Point point_projection(const Point& point) const; +#if ENABLE_6DOF_CAMERA + void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const; +#else void render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const; +#endif // ENABLE_6DOF_CAMERA private: void calc_bounding_boxes() const; diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index fa7a3be21..b22d27326 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -34,18 +34,27 @@ double Camera::FrustrumZMargin = 10.0; double Camera::MaxFovDeg = 60.0; Camera::Camera() +#if ENABLE_6DOF_CAMERA + : requires_zoom_to_bed(false) +#else : phi(45.0f) , requires_zoom_to_bed(false) , inverted_phi(false) +#endif // ENABLE_6DOF_CAMERA , m_type(Perspective) , m_target(Vec3d::Zero()) +#if !ENABLE_6DOF_CAMERA , m_theta(45.0f) +#endif // !ENABLE_6DOF_CAMERA , m_zoom(1.0) , m_distance(DefaultDistance) , m_gui_scale(1.0) , m_view_matrix(Transform3d::Identity()) , m_projection_matrix(Transform3d::Identity()) { +#if ENABLE_6DOF_CAMERA + set_default_orientation(); +#endif // ENABLE_6DOF_CAMERA } std::string Camera::get_type_as_string() const @@ -91,6 +100,9 @@ void Camera::select_next_type() void Camera::set_target(const Vec3d& target) { +#if ENABLE_6DOF_CAMERA + translate_world(target - m_target); +#else BoundingBoxf3 test_box = m_scene_box; test_box.translate(-m_scene_box.center()); // We may let this factor be customizable @@ -101,8 +113,10 @@ void Camera::set_target(const Vec3d& target) m_target(0) = clamp(test_box.min(0), test_box.max(0), target(0)); m_target(1) = clamp(test_box.min(1), test_box.max(1), target(1)); m_target(2) = clamp(test_box.min(2), test_box.max(2), target(2)); +#endif // ENABLE_6DOF_CAMERA } +#if !ENABLE_6DOF_CAMERA void Camera::set_theta(float theta, bool apply_limit) { if (apply_limit) @@ -114,6 +128,7 @@ void Camera::set_theta(float theta, bool apply_limit) m_theta += 360.0f; } } +#endif // !ENABLE_6DOF_CAMERA void Camera::update_zoom(double delta_zoom) { @@ -130,7 +145,25 @@ void Camera::set_zoom(double zoom) // Don't allow to zoom too close to the scene. m_zoom = std::min(zoom, 100.0); } - +#if ENABLE_6DOF_CAMERA +void Camera::select_view(const std::string& direction) +{ + if (direction == "iso") + set_default_orientation(); + else if (direction == "left") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ()); + else if (direction == "right") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ()); + else if (direction == "top") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY()); + else if (direction == "bottom") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY()); + else if (direction == "front") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ()); + else if (direction == "rear") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ()); +} +#else bool Camera::select_view(const std::string& direction) { const float* dir_vec = nullptr; @@ -159,6 +192,7 @@ bool Camera::select_view(const std::string& direction) else return false; } +#endif // ENABLE_6DOF_CAMERA double Camera::get_fov() const { @@ -180,20 +214,26 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const void Camera::apply_view_matrix() const { +#if !ENABLE_6DOF_CAMERA double theta_rad = Geometry::deg2rad(-(double)m_theta); double phi_rad = Geometry::deg2rad((double)phi); double sin_theta = ::sin(theta_rad); Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); +#endif // !ENABLE_6DOF_CAMERA glsafe(::glMatrixMode(GL_MODELVIEW)); glsafe(::glLoadIdentity()); +#if ENABLE_6DOF_CAMERA + glsafe(::glMultMatrixd(m_view_matrix.data())); +#else glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw glsafe(::glTranslated(-camera_pos(0), -camera_pos(1), -camera_pos(2))); glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); +#endif // ENABLE_6DOF_CAMERA } void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const @@ -300,7 +340,11 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) { m_zoom = zoom; // center view around box center +#if ENABLE_6DOF_CAMERA + set_target(box.center()); +#else m_target = box.center(); +#endif // ENABLE_6DOF_CAMERA } } @@ -313,7 +357,11 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canv { m_zoom = zoom; // center view around the calculated center +#if ENABLE_6DOF_CAMERA + set_target(center); +#else m_target = center; +#endif // ENABLE_6DOF_CAMERA } } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -360,6 +408,43 @@ void Camera::debug_render() const } #endif // ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA +void Camera::translate_world(const Vec3d& displacement) +{ + Vec3d new_target = validate_target(m_target + displacement); + Vec3d new_displacement = new_target - m_target; + if (!new_displacement.isApprox(Vec3d::Zero())) + { + m_target += new_displacement; + m_view_matrix.translate(-new_displacement); + } +} + +void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit) +{ + Vec3d target = m_target; + translate_world(-target); + m_view_matrix.rotate(Eigen::AngleAxisd(delta_zenit_rad, get_dir_right())); + m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ())); + translate_world(target); +} + +void Camera::rotate_local_around_target(const Vec3d& rotation_rad) +{ + Vec3d target = m_target; + translate_world(-target); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right())); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up())); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward())); + translate_world(target); +} + +bool Camera::is_looking_downward() const +{ + return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; +} +#endif // ENABLE_6DOF_CAMERA + std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const { std::pair ret; @@ -540,6 +625,63 @@ void Camera::set_distance(double distance) const apply_view_matrix(); } +#if ENABLE_6DOF_CAMERA +Transform3d Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const +{ + Vec3d unit_z = (position - target).normalized(); + Vec3d unit_x = up.cross(unit_z).normalized(); + Vec3d unit_y = unit_z.cross(unit_x).normalized(); + + Transform3d matrix; + + matrix(0, 0) = unit_x(0); + matrix(0, 1) = unit_x(1); + matrix(0, 2) = unit_x(2); + matrix(0, 3) = -unit_x.dot(position); + + matrix(1, 0) = unit_y(0); + matrix(1, 1) = unit_y(1); + matrix(1, 2) = unit_y(2); + matrix(1, 3) = -unit_y.dot(position); + + matrix(2, 0) = unit_z(0); + matrix(2, 1) = unit_z(1); + matrix(2, 2) = unit_z(2); + matrix(2, 3) = -unit_z.dot(position); + + matrix(3, 0) = 0.0; + matrix(3, 1) = 0.0; + matrix(3, 2) = 0.0; + matrix(3, 3) = 1.0; + + return matrix; +} + +void Camera::set_default_orientation() +{ + double theta_rad = Geometry::deg2rad(-45.0); + double phi_rad = Geometry::deg2rad(45.0); + double sin_theta = ::sin(theta_rad); + Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); + m_view_matrix = Transform3d::Identity(); + m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos); +} + +Vec3d Camera::validate_target(const Vec3d& target) const +{ + BoundingBoxf3 test_box = m_scene_box; + test_box.translate(-m_scene_box.center()); + // We may let this factor be customizable + static const double ScaleFactor = 1.5; + test_box.scale(ScaleFactor); + test_box.translate(m_scene_box.center()); + + return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)), + std::clamp(target(1), test_box.min(1), test_box.max(1)), + std::clamp(target(2), test_box.min(2), test_box.max(2))); +} +#endif // ENABLE_6DOF_CAMERA + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 6cd1b75a5..cfb0fd797 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -30,21 +30,29 @@ struct Camera Num_types }; +#if !ENABLE_6DOF_CAMERA float phi; - bool requires_zoom_to_bed; bool inverted_phi; +#endif // !ENABLE_6DOF_CAMERA + bool requires_zoom_to_bed; private: EType m_type; Vec3d m_target; +#if !ENABLE_6DOF_CAMERA float m_theta; +#endif // !ENABLE_6DOF_CAMERA double m_zoom; // Distance between camera position and camera target measured along the camera Z axis mutable double m_distance; mutable double m_gui_scale; mutable std::array m_viewport; +#if ENABLE_6DOF_CAMERA + Transform3d m_view_matrix; +#else mutable Transform3d m_view_matrix; +#endif // ENABLE_6DOF_CAMERA mutable Transform3d m_projection_matrix; mutable std::pair m_frustrum_zs; @@ -66,8 +74,10 @@ public: double get_distance() const { return m_distance; } double get_gui_scale() const { return m_gui_scale; } +#if !ENABLE_6DOF_CAMERA float get_theta() const { return m_theta; } void set_theta(float theta, bool apply_limit); +#endif // !ENABLE_6DOF_CAMERA double get_zoom() const { return m_zoom; } void update_zoom(double delta_zoom); @@ -76,7 +86,11 @@ public: const BoundingBoxf3& get_scene_box() const { return m_scene_box; } void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } +#if ENABLE_6DOF_CAMERA + void select_view(const std::string& direction); +#else bool select_view(const std::string& direction); +#endif // ENABLE_6DOF_CAMERA const std::array& get_viewport() const { return m_viewport; } const Transform3d& get_view_matrix() const { return m_view_matrix; } @@ -110,6 +124,21 @@ public: void debug_render() const; #endif // ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA + // translate the camera in world space + void translate_world(const Vec3d& displacement); + + // rotate the camera on a sphere having center == m_target and radius == m_distance + // using the given variations of spherical coordinates + void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit); + + // rotate the camera around three axes parallel to the camera local axes and passing through m_target + void rotate_local_around_target(const Vec3d& rotation_rad); + + // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis + bool is_looking_downward() const; +#endif // ENABLE_6DOF_CAMERA + private: // returns tight values for nearZ and farZ plane around the given bounding box // the camera MUST be outside of the bounding box in eye coordinate of the given box @@ -121,6 +150,12 @@ private: double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; #endif // ENABLE_THUMBNAIL_GENERATOR void set_distance(double distance) const; + +#if ENABLE_6DOF_CAMERA + Transform3d look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const; + void set_default_orientation(); + Vec3d validate_target(const Vec3d& target) const; +#endif // ENABLE_6DOF_CAMERA }; } // GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d2428cf96..860eab0fb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1792,8 +1792,14 @@ void GLCanvas3D::zoom_to_selection() void GLCanvas3D::select_view(const std::string& direction) { +#if ENABLE_6DOF_CAMERA + m_camera.select_view(direction); + if (m_canvas != nullptr) + m_canvas->Refresh(); +#else if (m_camera.select_view(direction) && (m_canvas != nullptr)) m_canvas->Refresh(); +#endif // ENABLE_6DOF_CAMERA } void GLCanvas3D::update_volumes_colors_by_extruder() @@ -1850,10 +1856,12 @@ void GLCanvas3D::render() GLfloat position_top[4] = { -0.5f, -0.5f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT0, GL_POSITION, position_top)); +#if !ENABLE_6DOF_CAMERA float theta = m_camera.get_theta(); if (theta > 180.f) // absolute value of the rotation theta = 360.f - theta; +#endif // !ENABLE_6DOF_CAMERA wxGetApp().imgui()->new_frame(); @@ -1878,7 +1886,11 @@ void GLCanvas3D::render() _render_objects(); _render_sla_slices(); _render_selection(); +#if ENABLE_6DOF_CAMERA + _render_bed(!m_camera.is_looking_downward(), true); +#else _render_bed(theta, true); +#endif // ENABLE_6DOF_CAMERA #if ENABLE_RENDER_SELECTION_CENTER _render_selection_center(); @@ -3213,7 +3225,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag if (m_selection.contains_volume(get_first_hover_volume_idx())) { +#if ENABLE_6DOF_CAMERA + if (std::abs(m_camera.get_dir_forward()(2)) < EPSILON) +#else if (m_camera.get_theta() == 90.0f) +#endif // ENABLE_6DOF_CAMERA { // side view -> move selected volumes orthogonally to camera view direction Linef3 ray = mouse_ray(pos); @@ -3273,9 +3289,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined()) { const Vec3d& orig = m_mouse.drag.start_position_3D; +#if ENABLE_6DOF_CAMERA + m_camera.rotate_on_sphere(Geometry::deg2rad((pos(0) - orig(0))* (double)TRACKBALLSIZE), + Geometry::deg2rad((pos(1) - orig(1))* (double)TRACKBALLSIZE), + wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#else float sign = m_camera.inverted_phi ? -1.0f : 1.0f; m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE; m_camera.set_theta(m_camera.get_theta() - ((float)pos(1) - (float)orig(1)) * TRACKBALLSIZE, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#endif // ENABLE_6DOF_CAMERA m_dirty = true; } m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); @@ -3325,9 +3347,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!evt.ShiftDown() && m_picking_enabled) deselect_all(); } +#if !ENABLE_6DOF_CAMERA else if (evt.LeftUp() && m_mouse.dragging) // Flips X mouse deltas if bed is upside down m_camera.inverted_phi = (m_camera.get_dir_up()(2) < 0.0); +#endif // !ENABLE_6DOF_CAMERA else if (evt.RightUp()) { m_mouse.position = pos.cast(); @@ -3932,6 +3956,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool Camera camera; camera.set_type(Camera::Ortho); +#if ENABLE_6DOF_CAMERA + camera.set_scene_box(scene_bounding_box()); +#endif // ENABLE_6DOF_CAMERA camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height); camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); camera.apply_view_matrix(); @@ -3982,7 +4009,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool glsafe(::glDisable(GL_DEPTH_TEST)); if (show_bed) +#if ENABLE_6DOF_CAMERA + _render_bed(!camera.is_looking_downward(), false); +#else _render_bed(camera.get_theta(), false); +#endif // ENABLE_6DOF_CAMERA if (transparent_background) glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 8485c4b27..3dd12e021 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -168,12 +168,17 @@ bool Mouse3DController::State::apply(Camera& camera) if (has_rotation()) { +#if ENABLE_6DOF_CAMERA + Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast(); + camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1)))); +#else const Vec3f& rotation = m_rotation.queue.front(); float theta = m_rotation_params.scale * rotation(0); float phi = m_rotation_params.scale * rotation(2); float sign = camera.inverted_phi ? -1.0f : 1.0f; camera.phi += sign * phi; camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#endif // ENABLE_6DOF_CAMERA m_rotation.queue.pop(); ret = true; } @@ -877,9 +882,15 @@ bool Mouse3DController::handle_packet_translation(const DataPacket& packet) bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte) { double deadzone = (double)m_state.get_rotation_deadzone(); +#if ENABLE_6DOF_CAMERA + Vec3f rotation((float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone), + (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone), + (float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone)); +#else Vec3f rotation(-(float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone), (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone), -(float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone)); +#endif // ENABLE_6DOF_CAMERA if (!rotation.isApprox(Vec3f::Zero())) { diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 13be48289..224f5007d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2004,7 +2004,11 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co const float max_y = box.max(1) + Margin; // view dependend order of rendering to keep correct transparency +#if ENABLE_6DOF_CAMERA + bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward(); +#else bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f; +#endif // ENABLE_6DOF_CAMERA float z1 = camera_on_top ? min_z : max_z; float z2 = camera_on_top ? max_z : min_z; From 15f873dd74824b1a35c44eb4e9333658f300fc79 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 15 Jan 2020 15:35:56 +0100 Subject: [PATCH 50/85] DoubleSlider: Implemented code for check of used extruders for MustiAsSingle mode --- src/libslic3r/GCode/ToolOrdering.cpp | 3 ++- src/libslic3r/Print.hpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 21 ++++++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index a76f0fafb..27abc359a 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -486,7 +486,8 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) print_z_below = it_lt_below->print_z; if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) { // The custom G-code applies to the current layer. - if (custom_gcode.gcode != ColorChangeCode || extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) + if ( custom_gcode.gcode != ColorChangeCode || + (custom_gcode.extruder <= num_extruders && extruder_printing_above[unsigned(custom_gcode.extruder - 1)])) // If it is color change, it will actually be useful as the exturder above will print. lt.custom_gcode = &custom_gcode; // Consume that custom G-code event. diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 42f8d761e..3d1f596d1 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -382,6 +382,7 @@ public: // Accessed by SupportMaterial const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } + const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } // #ys_FIXME just for testing protected: // methods for handling regions diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 3872db3fb..8e1cd0c6f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -5,6 +5,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" #include #include @@ -3487,7 +3488,25 @@ int DoubleSlider::get_extruder_for_tick(int tick) std::set DoubleSlider::get_used_extruders_for_tick(int tick) { if (m_mode == mmMultiExtruder) - return {}; // #ys_FIXME: correct fill used_extruders_for_tick for mmMultiExtruder + { + // #ys_FIXME: get tool ordering from _correct_ place + const Slic3r::ToolOrdering& tool_ordering = Slic3r::GUI::wxGetApp().plater()->fff_print().get_tool_ordering(); + + if (tool_ordering.empty()) + return {}; + + std::set used_extruders; + + auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), Slic3r::LayerTools(m_values[tick])); + for (; it_layer_tools != tool_ordering.end(); it_layer_tools++) + { + const std::vector& extruders = it_layer_tools->extruders; + for (const auto& extruder : extruders) + used_extruders.emplace(extruder+1); + } + + return used_extruders; + } const int default_initial_extruder = m_mode == mmMultiAsSingle ? std::max(m_only_extruder, 1) : 1; if (m_ticks.empty()) From 8e5ba5ccc5fe9720fde7441aea3654f538539a76 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 15 Jan 2020 16:20:16 +0100 Subject: [PATCH 51/85] Added synonyms to some PrintSteps: psWipeTower now equals to new psToolOrdering indicating that the ToolOrdering has been calculated (only if non-sequential mode is active). psBrim now equals to new psExtrusionPaths psExtrusionPaths shall be the last step before psWipeTower, indicating that all the printing extrusions are calculated for the G-code preview slider to edit the custom per print_z color changes, tool changes etc. --- src/libslic3r/GCode.cpp | 5 ++-- src/libslic3r/GCode/ToolOrdering.cpp | 3 ++ src/libslic3r/GCode/ToolOrdering.hpp | 7 ++++- src/libslic3r/Print.cpp | 44 ++++++++++++++++++++++++++-- src/libslic3r/Print.hpp | 19 ++++++++++-- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 870749867..7627f581d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1222,9 +1222,8 @@ void GCode::_do_export(Print& print, FILE* file) } else { // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. - tool_ordering = print.wipe_tower_data().tool_ordering.empty() ? - ToolOrdering(print, initial_extruder_id, false) : - print.wipe_tower_data().tool_ordering; + tool_ordering = print.tool_ordering(); + tool_ordering.assign_custom_gcodes(print); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? // The priming towers will be skipped. diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index a76f0fafb..2628e1926 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -460,6 +460,9 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) // If multiple events are planned over a span of a single layer, use the last one. void ToolOrdering::assign_custom_gcodes(const Print &print) { + // Only valid for non-sequential print. + assert(! print.config().complete_objects.value); + const std::vector &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; if (custom_gcode_per_print_z.empty()) return; diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index a9d5a98e7..08dd72656 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -143,6 +143,12 @@ public: void clear() { m_layer_tools.clear(); } + // Only valid for non-sequential print: + // Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools. + // Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer. + // If multiple events are planned over a span of a single layer, use the last one. + void assign_custom_gcodes(const Print &print); + // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. unsigned int first_extruder() const { return m_first_printing_extruder; } @@ -170,7 +176,6 @@ private: void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); - void assign_custom_gcodes(const Print &print); std::vector m_layer_tools; // First printing extruder, including the multi-material priming sequence. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ed8817882..babdd5aa4 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -478,7 +478,7 @@ static std::vector print_objects_from_model_object(const ModelOb // Compare just the layer ranges and their layer heights, not the associated configs. // Ignore the layer heights if check_layer_heights is false. -bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height) +static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height) { if (lr1.size() != lr2.size()) return false; @@ -493,6 +493,37 @@ bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_c return true; } +// Returns true if va == vb when all CustomGCode items that are not ExtruderChangeCode are ignored. +static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector &va, const std::vector &vb) +{ + auto it_a = va.begin(); + auto it_b = vb.begin(); + while (it_a != va.end() && it_b != vb.end()) { + if (it_a != va.end() && it_a->gcode != ExtruderChangeCode) { + // Skip any CustomGCode items, which are not tool changes. + ++ it_a; + continue; + } + if (it_b != vb.end() && it_b->gcode != ExtruderChangeCode) { + // Skip any CustomGCode items, which are not tool changes. + ++ it_b; + continue; + } + if (it_a == va.end() || it_b == vb.end()) + // va or vb contains more Tool Changes than the other. + return true; + assert(it_a->gcode == ExtruderChangeCode); + assert(it_b->gcode == ExtruderChangeCode); + if (*it_a != *it_b) + // The two Tool Changes differ. + return true; + ++ it_a; + ++ it_b; + } + // There is no change in custom Tool Changes. + return false; +} + // Collect diffs of configuration values at various containers, // resolve the filament rectract overrides of extruder retract values. void Print::config_diffs( @@ -692,8 +723,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object_status.emplace(model_object->id(), ModelObjectStatus::New); } else { if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) { - // If custom gcode per layer height was changed, we should stop background processing. - update_apply_status(this->invalidate_steps({ psWipeTower, psGCodeExport })); + update_apply_status(custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z, model.custom_gcode_per_print_z) ? + // The Tool Ordering and the Wipe Tower are no more valid. + this->invalidate_steps({ psWipeTower, psGCodeExport }) : + // There is no change in Tool Changes stored in custom_gcode_per_print_z, therefore there is no need to update Tool Ordering. + this->invalidate_step(psGCodeExport)); m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; } if (model_object_list_equal(m_model, model)) { @@ -1521,9 +1555,13 @@ void Print::process() obj->generate_support_material(); if (this->set_started(psWipeTower)) { m_wipe_tower_data.clear(); + m_tool_ordering.clear(); if (this->has_wipe_tower()) { //this->set_status(95, L("Generating wipe tower")); this->_make_wipe_tower(); + } else if (! this->config().complete_objects.value) { + // Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches. + m_tool_ordering = ToolOrdering(*this, -1, false); } this->set_done(psWipeTower); } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 42f8d761e..4a4ed3964 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -27,8 +27,19 @@ class GCodePreviewData; // Print step IDs for keeping track of the print state. enum PrintStep { - psSkirt, psBrim, psWipeTower, psGCodeExport, psCount, + psSkirt, + psBrim, + // Synonym for the last step before the Wipe Tower / Tool Ordering, for the G-code preview slider to understand that + // all the extrusions are there for the layer slider to add color changes etc. + psExtrusionPaths = psBrim, + psWipeTower, + // psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering, + // while if printing without the Wipe Tower, the ToolOrdering is calculated as well. + psToolOrdering = psWipeTower, + psGCodeExport, + psCount, }; + enum PrintObjectStep { posSlice, posPerimeters, posPrepareInfill, posInfill, posSupportMaterial, posCount, @@ -231,6 +242,7 @@ private: struct WipeTowerData { + WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); } // Following section will be consumed by the GCodeGenerator. // Tool ordering of a non-sequential print has to be known to calculate the wipe tower. // Cache it here, so it does not need to be recalculated during the G-code generation. @@ -247,7 +259,6 @@ struct WipeTowerData float brim_width; void clear() { - tool_ordering.clear(); priming.reset(nullptr); tool_changes.clear(); final_purge.reset(nullptr); @@ -377,6 +388,7 @@ public: // Wipe tower support. bool has_wipe_tower() const; const WipeTowerData& wipe_tower_data(size_t extruders_cnt = 0, double first_layer_height = 0., double nozzle_diameter = 0.) const; + const ToolOrdering& tool_ordering() const { return m_tool_ordering; } std::string output_filename(const std::string &filename_base = std::string()) const override; @@ -420,7 +432,8 @@ private: ExtrusionEntityCollection m_brim; // Following section will be consumed by the GCodeGenerator. - WipeTowerData m_wipe_tower_data; + ToolOrdering m_tool_ordering; + WipeTowerData m_wipe_tower_data {m_tool_ordering}; // Estimated print time, filament consumed. PrintStatistics m_print_statistics; From 9df7eb4e08872edcd9a47fc8fd3ef5d3cb8e29f6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 09:12:36 +0100 Subject: [PATCH 52/85] Customizable use of 6 dof camera --- src/slic3r/GUI/AppConfig.cpp | 5 +++++ src/slic3r/GUI/Camera.cpp | 13 ++++++++++++- src/slic3r/GUI/Camera.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++++++--- src/slic3r/GUI/Preferences.cpp | 9 +++++++++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index d277fc095..12302a5dc 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -87,6 +87,11 @@ void AppConfig::set_defaults() if (get("use_perspective_camera").empty()) set("use_perspective_camera", "1"); +#if ENABLE_6DOF_CAMERA + if (get("use_free_camera").empty()) + set("use_free_camera", "0"); +#endif // ENABLE_6DOF_CAMERA + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index b22d27326..49246dbb9 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -6,6 +6,11 @@ #endif // !ENABLE_THUMBNAIL_GENERATOR #include "GUI_App.hpp" #include "AppConfig.hpp" +#if ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA +#include "Mouse3DController.hpp" +#endif // ENABLE_6DOF_CAMERA +#endif // ENABLE_CAMERA_STATISTICS #include @@ -373,6 +378,12 @@ void Camera::debug_render() const imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); std::string type = get_type_as_string(); +#if ENABLE_6DOF_CAMERA + if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1")) + type += "/free"; + else + type += "/constrained"; +#endif // ENABLE_6DOF_CAMERA Vec3f position = get_position().cast(); Vec3f target = m_target.cast(); float distance = (float)get_distance(); @@ -420,7 +431,7 @@ void Camera::translate_world(const Vec3d& displacement) } } -void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit) +void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad) { Vec3d target = m_target; translate_world(-target); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index cfb0fd797..67c97c0b4 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -130,7 +130,7 @@ public: // rotate the camera on a sphere having center == m_target and radius == m_distance // using the given variations of spherical coordinates - void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit); + void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad); // rotate the camera around three axes parallel to the camera local axes and passing through m_target void rotate_local_around_target(const Vec3d& rotation_rad); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 860eab0fb..1c383841e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3290,9 +3290,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { const Vec3d& orig = m_mouse.drag.start_position_3D; #if ENABLE_6DOF_CAMERA - m_camera.rotate_on_sphere(Geometry::deg2rad((pos(0) - orig(0))* (double)TRACKBALLSIZE), - Geometry::deg2rad((pos(1) - orig(1))* (double)TRACKBALLSIZE), - wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); + double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE; + double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE; + if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1")) + m_camera.rotate_local_around_target(Vec3d(y, x, 0.0)); + else + m_camera.rotate_on_sphere(x, y); #else float sign = m_camera.inverted_phi ? -1.0f : 1.0f; m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 295c1a6ec..d0686677d 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -124,6 +124,15 @@ void PreferencesDialog::build() option = Option(def, "use_perspective_camera"); m_optgroup->append_single_option_line(option); +#if ENABLE_6DOF_CAMERA + def.label = L("Use free camera"); + def.type = coBool; + def.tooltip = L("If enabled, use free camera. If not enabled, use constrained camera."); + def.set_default_value(new ConfigOptionBool(app_config->get("use_free_camera") == "1")); + option = Option(def, "use_free_camera"); + m_optgroup->append_single_option_line(option); +#endif // ENABLE_6DOF_CAMERA + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); From 3f2ccf08d28e5fc8fd0c4443f4d39869ed095e7d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 10:17:07 +0100 Subject: [PATCH 53/85] 3Dconnexion devices translation linearly dependent on zoom --- src/slic3r/GUI/Camera.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 24 ++++++++--------------- src/slic3r/GUI/GLSelectionRectangle.cpp | 3 +-- src/slic3r/GUI/GLToolbar.cpp | 18 ++++++----------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/Mouse3DController.cpp | 2 +- 6 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 67c97c0b4..257b27901 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -80,6 +80,7 @@ public: #endif // !ENABLE_6DOF_CAMERA double get_zoom() const { return m_zoom; } + double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; } void update_zoom(double delta_zoom); void set_zoom(double zoom); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1c383841e..617ceb4ba 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -390,8 +390,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); @@ -407,8 +406,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); } @@ -468,8 +466,7 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas const float width = (float)m_tooltip_texture.get_width() * scale; const float height = (float)m_tooltip_texture.get_height() * scale; - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float gap = 10.0f * inv_zoom; float bar_left = bar_rect.get_left(); @@ -964,8 +961,7 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float left = (-0.5f * (float)m_original_width) * inv_zoom; float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom; float right = left + (float)m_original_width * inv_zoom; @@ -1327,8 +1323,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; float right = left + (float)m_original_width * inv_zoom; @@ -4973,8 +4968,7 @@ void GLCanvas3D::_render_main_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom; @@ -5000,8 +4994,7 @@ void GLCanvas3D::_render_undoredo_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom; @@ -5023,8 +5016,7 @@ void GLCanvas3D::_render_view_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); // places the toolbar on the bottom-left corner of the 3d scene float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 684563bff..a8b69d75a 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -69,8 +69,7 @@ namespace GUI { return; const Camera& camera = canvas.get_camera(); - float zoom = (float)camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)camera.get_inv_zoom(); Size cnv_size = canvas.get_canvas_size(); float cnv_half_width = 0.5f * (float)cnv_size.get_width(); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 82ac82515..d1edff10f 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -653,8 +653,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -758,8 +757,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -875,8 +873,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -949,8 +946,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -1102,8 +1098,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; @@ -1151,8 +1146,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index abcb39c14..ed8d16aa2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -850,7 +850,7 @@ void GLGizmosManager::do_render_overlay() const float cnv_w = (float)m_parent.get_canvas_size().get_width(); float cnv_h = (float)m_parent.get_canvas_size().get_height(); float zoom = (float)m_parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_parent.get_camera().get_inv_zoom(); float height = get_scaled_total_height(); float width = get_scaled_total_width(); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 3dd12e021..6de2c0850 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -156,7 +156,7 @@ bool Mouse3DController::State::apply(Camera& camera) { const Vec3d& translation = m_translation.queue.front(); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); + camera.set_target(camera.get_target() + camera.get_inv_zoom() * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); if (translation(1) != 0.0) camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1))); #else From 8ef29aab78ebbf862914eff14b5e111a4b065e9a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 16 Jan 2020 10:20:36 +0100 Subject: [PATCH 54/85] Refactoring of DoubleSlider::add_code() --- src/slic3r/GUI/wxExtensions.cpp | 96 ++++++++++++++++----------------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8e1cd0c6f..f2fed3bf7 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -3652,66 +3652,60 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick auto it = m_ticks.find(TICK_CODE{ tick }); - if (it == m_ticks.end()) + if (it != m_ticks.end()) + return; + + std::string color; + const int extruder = selected_extruder > 0 ? selected_extruder : std::max(1, m_only_extruder); + + if (code == Slic3r::ColorChangeCode) { - std::string color = ""; - if (code == Slic3r::ColorChangeCode) + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + + if (m_ticks.empty()) + color = colors[extruder-1]; + else { - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - - if (m_ticks.empty()) - color = colors[selected_extruder > 0 ? selected_extruder - 1 : std::max(1, m_only_extruder)-1]; - else - { - auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick }); - while (before_tick_it != m_ticks.begin()) { - --before_tick_it; - if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == selected_extruder) { - color = before_tick_it->color; - break; - } + auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick }); + while (before_tick_it != m_ticks.begin()) { + --before_tick_it; + if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) { + color = before_tick_it->color; + break; } - - if (color.empty()) - color = colors[selected_extruder > 0 ? selected_extruder - 1 : std::max(1, m_only_extruder) - 1]; } - color = get_new_color(color); if (color.empty()) - return; - } - else if (code == Slic3r::PausePrintCode) - { - /* PausePrintCode doesn't need a color, so - * this field is used for save a short message shown on Printer display - * */ - color = get_pause_print_msg(m_pause_print_msg, m_values[tick]); - if (color.empty()) - return; - m_pause_print_msg = color; - } - else if (code.empty()) - { - code = get_custom_code(m_custom_gcode, m_values[tick]); - if (code.empty()) - return; - m_custom_gcode = code; + color = colors[extruder-1]; } - int extruder = 1; - if (m_mode != mmSingleExtruder) { - if (code == Slic3r::ColorChangeCode && selected_extruder >= 0) - extruder = selected_extruder; - else - extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); - } - - m_ticks.emplace(TICK_CODE{tick, code, extruder, color}); - - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); - Refresh(); - Update(); + color = get_new_color(color); + if (color.empty()) + return; } + else if (code == Slic3r::PausePrintCode) + { + /* PausePrintCode doesn't need a color, so + * this field is used for save a short message shown on Printer display + * */ + color = get_pause_print_msg(m_pause_print_msg, m_values[tick]); + if (color.empty()) + return; + m_pause_print_msg = color; + } + else if (code.empty()) + { + code = get_custom_code(m_custom_gcode, m_values[tick]); + if (code.empty()) + return; + m_custom_gcode = code; + } + + m_ticks.emplace(TICK_CODE{tick, code, extruder, color}); + + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + Refresh(); + Update(); } void DoubleSlider::edit_tick() From 89166accbe19c3599fb7c7102bc7d60a973213ed Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 11:08:19 +0100 Subject: [PATCH 55/85] Modified layout of preferences dialog --- src/slic3r/GUI/Preferences.cpp | 82 ++++++++++++++++++++-------------- src/slic3r/GUI/Preferences.hpp | 6 ++- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index d0686677d..4fd63fe0e 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -19,16 +19,11 @@ PreferencesDialog::PreferencesDialog(wxWindow* parent) : void PreferencesDialog::build() { auto app_config = get_app_config(); - m_optgroup = std::make_shared(this, _(L("General"))); - m_optgroup->label_width = 40; - m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_optgroup_general = std::make_shared(this, _(L("General"))); + m_optgroup_general->label_width = 40; + m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) { m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; - - if (opt_key == "use_custom_toolbar_size") { - m_icon_size_sizer->ShowItems(boost::any_cast(value)); - this->layout(); - } - }; + }; // TODO // $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( @@ -47,7 +42,7 @@ void PreferencesDialog::build() "instead of the one containing the input files."); def.set_default_value(new ConfigOptionBool{ app_config->has("remember_output_path") ? app_config->get("remember_output_path") == "1" : true }); Option option(def, "remember_output_path"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Auto-center parts"); def.type = coBool; @@ -55,7 +50,7 @@ void PreferencesDialog::build() "around the print bed center."); def.set_default_value(new ConfigOptionBool{ app_config->get("autocenter") == "1" }); option = Option (def,"autocenter"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Background processing"); def.type = coBool; @@ -63,7 +58,7 @@ void PreferencesDialog::build() "as they\'re loaded in order to save time when exporting G-code."); def.set_default_value(new ConfigOptionBool{ app_config->get("background_processing") == "1" }); option = Option (def,"background_processing"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); // Please keep in sync with ConfigWizard def.label = L("Check for application updates"); @@ -71,7 +66,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, PrusaSlicer will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done."); def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1")); option = Option (def, "version_check"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Please keep in sync with ConfigWizard @@ -80,7 +75,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked."); def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1")); option = Option(def, "export_sources_full_pathnames"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Please keep in sync with ConfigWizard @@ -89,7 +84,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup."); def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1")); option = Option (def, "preset_update"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Suppress \" - default - \" presets"); def.type = coBool; @@ -97,7 +92,7 @@ void PreferencesDialog::build() "selections once there are any other valid presets available."); def.set_default_value(new ConfigOptionBool{ app_config->get("no_defaults") == "1" }); option = Option (def,"no_defaults"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Show incompatible print and filament presets"); def.type = coBool; @@ -105,7 +100,7 @@ void PreferencesDialog::build() "even if they are marked as incompatible with the active printer"); def.set_default_value(new ConfigOptionBool{ app_config->get("show_incompatible_presets") == "1" }); option = Option (def,"show_incompatible_presets"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #if __APPLE__ def.label = L("Use Retina resolution for the 3D scene"); @@ -114,15 +109,21 @@ void PreferencesDialog::build() "If you are experiencing 3D performance problems, disabling this option may help."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_retina_opengl") == "1" }); option = Option (def, "use_retina_opengl"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #endif - def.label = L("Use perspective camera"); - def.type = coBool; - def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera."); - def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" }); - option = Option(def, "use_perspective_camera"); - m_optgroup->append_single_option_line(option); + m_optgroup_camera = std::make_shared(this, _(L("Camera"))); + m_optgroup_camera->label_width = 40; + m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + }; + + def.label = L("Use perspective camera"); + def.type = coBool; + def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera."); + def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" }); + option = Option(def, "use_perspective_camera"); + m_optgroup_camera->append_single_option_line(option); #if ENABLE_6DOF_CAMERA def.label = L("Use free camera"); @@ -130,21 +131,33 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, use free camera. If not enabled, use constrained camera."); def.set_default_value(new ConfigOptionBool(app_config->get("use_free_camera") == "1")); option = Option(def, "use_free_camera"); - m_optgroup->append_single_option_line(option); + m_optgroup_camera->append_single_option_line(option); #endif // ENABLE_6DOF_CAMERA + m_optgroup_gui = std::make_shared(this, _(L("GUI"))); + m_optgroup_gui->label_width = 40; + m_optgroup_gui->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + if (opt_key == "use_custom_toolbar_size") { + m_icon_size_sizer->ShowItems(boost::any_cast(value)); + this->layout(); + } + }; + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); - option = Option (def,"use_custom_toolbar_size"); - m_optgroup->append_single_option_line(option); + option = Option(def, "use_custom_toolbar_size"); + m_optgroup_gui->append_single_option_line(option); - create_icon_size_slider(); - m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1"); + create_icon_size_slider(); + m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1"); auto sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); SetFont(wxGetApp().normal_font()); @@ -176,7 +189,9 @@ void PreferencesDialog::accept() void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect) { - m_optgroup->msw_rescale(); + m_optgroup_general->msw_rescale(); + m_optgroup_camera->msw_rescale(); + m_optgroup_gui->msw_rescale(); msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL }); @@ -201,7 +216,7 @@ void PreferencesDialog::create_icon_size_slider() m_icon_size_sizer = new wxBoxSizer(wxHORIZONTAL); - wxWindow* parent = m_optgroup->ctrl_parent(); + wxWindow* parent = m_optgroup_gui->ctrl_parent(); if (isOSX) // For correct rendering of the slider and value label under OSX @@ -249,8 +264,9 @@ void PreferencesDialog::create_icon_size_slider() win->SetBackgroundStyle(wxBG_STYLE_PAINT); } - m_optgroup->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em); + m_optgroup_gui->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em); } + } // GUI } // Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 9fffe6a7f..35bf2b8c5 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -15,8 +15,10 @@ class ConfigOptionsGroup; class PreferencesDialog : public DPIDialog { std::map m_values; - std::shared_ptr m_optgroup; - wxSizer* m_icon_size_sizer; + std::shared_ptr m_optgroup_general; + std::shared_ptr m_optgroup_camera; + std::shared_ptr m_optgroup_gui; + wxSizer* m_icon_size_sizer; bool isOSX {false}; public: PreferencesDialog(wxWindow* parent); From a9529fbcdc314d4dc58b99cb53205dc6100538fd Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 12:00:54 +0100 Subject: [PATCH 56/85] Added method void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot) to rotate the camera around a generic point --- src/slic3r/GUI/Camera.cpp | 13 ++++++++++--- src/slic3r/GUI/Camera.hpp | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 49246dbb9..f2a560c08 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -442,12 +442,19 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad) void Camera::rotate_local_around_target(const Vec3d& rotation_rad) { - Vec3d target = m_target; - translate_world(-target); + rotate_local_around_pivot(rotation_rad, m_target); +} + +void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot) +{ + // we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target()) + // and m_target is modified by the translate_world() calls + Vec3d center = pivot; + translate_world(-center); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right())); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up())); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward())); - translate_world(target); + translate_world(center); } bool Camera::is_looking_downward() const diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 257b27901..87060e288 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -136,6 +136,9 @@ public: // rotate the camera around three axes parallel to the camera local axes and passing through m_target void rotate_local_around_target(const Vec3d& rotation_rad); + // rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point + void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot); + // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis bool is_looking_downward() const; #endif // ENABLE_6DOF_CAMERA From 1b354d8d3c83f2e97a8dc139db64a00ab5628569 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 16 Jan 2020 13:39:03 +0100 Subject: [PATCH 57/85] WIP: Enhancement of the FDM back end to support Color Change situations, when a project was switched from multi-extruder printer to single extruder printer. --- src/libslic3r/GCode/ToolOrdering.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 2628e1926..634093d72 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -129,8 +129,12 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. // Do it only if all the objects were configured to be printed with a single extruder. std::vector> per_layer_extruder_switches; - if (print.object_extruders().size() == 1) - per_layer_extruder_switches = custom_tool_changes(print.model(), (unsigned int)print.config().nozzle_diameter.size()); + if (auto num_extruders = unsigned(print.config().nozzle_diameter.size()); + num_extruders > 1 && print.object_extruders().size() == 1) { + // Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material). + // There may be custom per-layer tool changes available at the model. + per_layer_extruder_switches = custom_tool_changes(print.model(), num_extruders); + } // Collect extruders reuqired to print the layers. for (auto object : print.objects()) @@ -470,6 +474,8 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) unsigned int num_extruders = *std::max_element(m_all_printing_extruders.begin(), m_all_printing_extruders.end()) + 1; std::vector extruder_printing_above(num_extruders, false); auto custom_gcode_it = custom_gcode_per_print_z.rbegin(); + // If printing on a single extruder machine, make the tool changes trigger color change (M600) events. + bool tool_changes_as_color_changes = num_extruders == 1; // From the last layer to the first one: for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) { LayerTools < = *it_lt; @@ -489,7 +495,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) print_z_below = it_lt_below->print_z; if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) { // The custom G-code applies to the current layer. - if (custom_gcode.gcode != ColorChangeCode || extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) + if (tool_changes_as_color_changes || custom_gcode.gcode != ColorChangeCode || extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) // If it is color change, it will actually be useful as the exturder above will print. lt.custom_gcode = &custom_gcode; // Consume that custom G-code event. From 3acfae92e12611c3bd76c3623b6d9dcade399458 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 16 Jan 2020 14:59:16 +0100 Subject: [PATCH 58/85] Fix of recent wipe tower / tool ordering refactoring. --- src/libslic3r/GCode/ToolOrdering.cpp | 5 ----- src/libslic3r/Print.hpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 634093d72..2cc39583b 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -146,11 +146,6 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->fill_wipe_tower_partitions(print.config(), object_bottom_z); this->collect_extruder_statistics(prime_multi_material); - - // Assign custom G-code actions from Model::custom_gcode_per_print_z to their respecive layers, - // ignoring the extruder switches, which were processed above, and ignoring color changes for extruders, - // that do not print above their respective print_z. - this->assign_custom_gcodes(print); } void ToolOrdering::initialize_layers(std::vector &zs) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 4a4ed3964..5e6a26f9d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -242,11 +242,10 @@ private: struct WipeTowerData { - WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); } // Following section will be consumed by the GCodeGenerator. // Tool ordering of a non-sequential print has to be known to calculate the wipe tower. // Cache it here, so it does not need to be recalculated during the G-code generation. - ToolOrdering tool_ordering; + ToolOrdering &tool_ordering; // Cache of tool changes per print layer. std::unique_ptr> priming; std::vector> tool_changes; @@ -267,6 +266,14 @@ struct WipeTowerData depth = 0.f; brim_width = 0.f; } + +private: + // Only allow the WipeTowerData to be instantiated internally by Print, + // as this WipeTowerData shares reference to Print::m_tool_ordering. + friend class Print; + WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); } + WipeTowerData(const WipeTowerData & /* rhs */) = delete; + WipeTowerData &operator=(const WipeTowerData & /* rhs */) = delete; }; struct PrintStatistics From 89fcd7f95af4a078f86e5545b31fa9ae0fdd5091 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 16 Jan 2020 16:01:19 +0100 Subject: [PATCH 59/85] Added "mode" variable for custom_gcode_per_print_z --- src/libslic3r/Format/3mf.cpp | 8 ++++---- src/libslic3r/Format/AMF.cpp | 6 +++--- src/libslic3r/GCode/ToolOrdering.cpp | 10 +++++----- src/libslic3r/Model.cpp | 6 +++--- src/libslic3r/Model.hpp | 23 ++++++++++++++++++++++- src/libslic3r/Print.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 8 ++++---- src/slic3r/GUI/Plater.cpp | 6 +++--- src/slic3r/GUI/PresetBundle.cpp | 2 +- 10 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index cca90b463..ab4848c9a 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1088,7 +1088,7 @@ namespace Slic3r { return; pt::ptree code_tree = main_tree.front().second; - m_model->custom_gcode_per_print_z.clear(); + m_model->custom_gcode_per_print_z.gcodes.clear(); for (const auto& code : code_tree) { @@ -1100,7 +1100,7 @@ namespace Slic3r { int extruder = tree.get (".extruder" ); std::string color = tree.get (".color" ); - m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ; + m_model->custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ; } } } @@ -2631,12 +2631,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv { std::string out = ""; - if (!model.custom_gcode_per_print_z.empty()) + if (!model.custom_gcode_per_print_z.gcodes.empty()) { pt::ptree tree; pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", ""); - for (const Model::CustomGCode& code : model.custom_gcode_per_print_z) + for (const Model::CustomGCode& code : model.custom_gcode_per_print_z.gcodes) { pt::ptree& code_tree = main_tree.add("code", ""); // store minX and maxZ diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 947c04458..efb90f592 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -653,7 +653,7 @@ void AMFParserContext::endElement(const char * /* name */) int extruder = atoi(m_value[2].c_str()); const std::string& color = m_value[3]; - m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color}); + m_model.custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{height, gcode, extruder, color}); for (std::string& val: m_value) val.clear(); @@ -1250,14 +1250,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; } - if (!model->custom_gcode_per_print_z.empty()) + if (!model->custom_gcode_per_print_z.gcodes.empty()) { std::string out = ""; pt::ptree tree; pt::ptree& main_tree = tree.add("custom_gcodes_per_height", ""); - for (const Model::CustomGCode& code : model->custom_gcode_per_print_z) + for (const Model::CustomGCode& code : model->custom_gcode_per_print_z.gcodes) { pt::ptree& code_tree = main_tree.add("code", ""); // store minX and maxZ diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 51093c32a..fe8c93c9a 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -462,13 +462,13 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) // Only valid for non-sequential print. assert(! print.config().complete_objects.value); - const std::vector &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; - if (custom_gcode_per_print_z.empty()) + const Model::CustomGCodeInfo &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; + if (custom_gcode_per_print_z.gcodes.empty()) return; unsigned int num_extruders = *std::max_element(m_all_printing_extruders.begin(), m_all_printing_extruders.end()) + 1; std::vector extruder_printing_above(num_extruders, false); - auto custom_gcode_it = custom_gcode_per_print_z.rbegin(); + auto custom_gcode_it = custom_gcode_per_print_z.gcodes.rbegin(); // If printing on a single extruder machine, make the tool changes trigger color change (M600) events. bool tool_changes_as_color_changes = num_extruders == 1; // From the last layer to the first one: @@ -478,8 +478,8 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) for (unsigned int i : lt.extruders) extruder_printing_above[i] = true; // Skip all custom G-codes above this layer and skip all extruder switches. - for (; custom_gcode_it != custom_gcode_per_print_z.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ExtruderChangeCode); ++ custom_gcode_it); - if (custom_gcode_it == custom_gcode_per_print_z.rend()) + for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ExtruderChangeCode); ++ custom_gcode_it); + if (custom_gcode_it == custom_gcode_per_print_z.gcodes.rend()) // Custom G-codes were processed. break; // Some custom G-code is configured for this layer or a layer below. diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 812180641..ead2c95ca 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -126,7 +126,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c if (add_default_instances) model.add_default_instances(); - update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); + update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config); return model; } @@ -163,7 +163,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig if (add_default_instances) model.add_default_instances(); - update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); + update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config); return model; } @@ -1846,7 +1846,7 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const std::vector> custom_tool_changes(const Model &model, size_t num_extruders) { std::vector> custom_tool_changes; - for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z) + for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z.gcodes) if (custom_gcode.gcode == ExtruderChangeCode) { // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder)); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 26bb4cb92..509c70b15 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -772,7 +772,28 @@ public: std::string color; // if gcode is equal to PausePrintCode, // this field is used for save a short message shown on Printer display }; - std::vector custom_gcode_per_print_z; + + struct CustomGCodeInfo + { + enum MODE + { + SingleExtruder, // single extruder printer preset is selected + MultiAsSingle, // multiple extruder printer preset is selected, but + // this mode works just for Single extruder print + // (For all print from objects settings is used just one extruder) + MultiExtruder // multiple extruder printer preset is selected + } mode; + + std::vector gcodes; + + bool operator==(const CustomGCodeInfo& rhs) const + { + return (rhs.mode == this->mode ) && + (rhs.gcodes == this->gcodes ); + } + bool operator!=(const CustomGCodeInfo& rhs) const { return !(*this == rhs); } + } + custom_gcode_per_print_z; // Default constructor assigns a new ID to the model. Model() { assert(this->id().valid()); } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index babdd5aa4..08e43564f 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -723,7 +723,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object_status.emplace(model_object->id(), ModelObjectStatus::New); } else { if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) { - update_apply_status(custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z, model.custom_gcode_per_print_z) ? + update_apply_status(custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes) ? // The Tool Ordering and the Wipe Tower are no more valid. this->invalidate_steps({ psWipeTower, psGCodeExport }) : // There is no change in Tool Changes stored in custom_gcode_per_print_z, therefore there is no need to update Tool Ordering. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d2428cf96..fa34ff929 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1011,7 +1011,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D std::vector& colors, std::vector& cp_legend_items) { - std::vector custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z; + std::vector custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; const int extruders_cnt = wxGetApp().extruders_edited_cnt(); if (extruders_cnt == 1) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index fceaeba3b..f447127f8 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -564,7 +564,7 @@ void Preview::update_view_type(bool slice_completed) { const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config; - const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&& + const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes.empty() /*&& (wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */? _(L("Color Print")) : config.option("wiping_volumes_matrix")->values.size() > 1 ? @@ -595,7 +595,7 @@ void Preview::create_double_slider() Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { Model& model = wxGetApp().plater()->model(); - model.custom_gcode_per_print_z = m_slider->GetTicksValues(); + model.custom_gcode_per_print_z.gcodes = m_slider->GetTicksValues(); m_schedule_background_process(); update_view_type(false); @@ -664,7 +664,7 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min(); bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max(); - std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z; + std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; check_slider_values(ticks_from_model, layers_z); m_slider->SetSliderValues(layers_z); @@ -837,7 +837,7 @@ void Preview::load_print_as_fff(bool keep_z_range) colors.push_back("#808080"); // gray color for pause print or custom G-code if (!gcode_preview_data_valid) - color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z; + color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; } else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) ) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dc720ddae..6f77c1db6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2791,7 +2791,7 @@ void Plater::priv::reset() // The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here this->sidebar->show_sliced_info_sizer(false); - model.custom_gcode_per_print_z.clear(); + model.custom_gcode_per_print_z.gcodes.clear(); } void Plater::priv::mirror(Axis axis) @@ -5349,9 +5349,9 @@ std::vector Plater::get_extruder_colors_from_plater_config() const std::vector Plater::get_colors_for_color_print() const { std::vector colors = get_extruder_colors_from_plater_config(); - colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size()); + colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size()); - for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z) + for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z.gcodes) if (code.gcode == ColorChangeCode) colors.emplace_back(code.color); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 219d7b89d..8f5d58bc1 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -877,7 +877,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // 4) Load the project config values (the per extruder wipe matrix etc). this->project_config.apply_only(config, s_project_options); - update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config); + update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes, &this->project_config); break; } From 75c2b44d239d37ee32f781a769dbe2dc7c2e2191 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 16:02:40 +0100 Subject: [PATCH 60/85] Follow-up of merge of pull request #3293 -> Fixed link error and toolpaths role colors --- src/libslic3r/GCode/PreviewData.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 64057ec8d..15553c7dc 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -80,8 +80,8 @@ Color GCodePreviewData::RangeBase::get_color_at(float value) const constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1; // Compute the two colors just below (low) and above (high) the input value - const std::size_t color_low_idx = clamp(std::size_t{0}, color_max_idx, static_cast(global_t)); - const std::size_t color_high_idx = clamp(std::size_t{0}, color_max_idx, color_low_idx + 1); + const std::size_t color_low_idx = std::clamp(static_cast(global_t), std::size_t{ 0 }, color_max_idx); + const std::size_t color_high_idx = std::clamp(color_low_idx + 1, std::size_t{ 0 }, color_max_idx); const Color color_low = range_rainbow_colors[color_low_idx]; const Color color_high = range_rainbow_colors[color_high_idx]; @@ -302,7 +302,7 @@ void GCodePreviewData::set_extrusion_role_color(const std::string& role_name, fl void GCodePreviewData::set_extrusion_paths_colors(const std::vector& colors) { - unsigned int size = (unsigned int)range_rainbow_colors.size(); + unsigned int size = (unsigned int)colors.size(); if (size % 2 != 0) return; @@ -486,7 +486,7 @@ size_t GCodePreviewData::memory_used() const sizeof(shell) + sizeof(ranges); } -const std::vector& ColorPrintColors() +const std::vector& GCodePreviewData::ColorPrintColors() { static std::vector color_print = {"#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6"}; return color_print; @@ -494,18 +494,18 @@ const std::vector& ColorPrintColors() Color operator + (const Color& c1, const Color& c2) { - 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[2] + c2.rgba[2]), - clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3])); + return Color(std::clamp(c1.rgba[0] + c2.rgba[0], 0.0f, 1.0f), + std::clamp(c1.rgba[1] + c2.rgba[1], 0.0f, 1.0f), + std::clamp(c1.rgba[2] + c2.rgba[2], 0.0f, 1.0f), + std::clamp(c1.rgba[3] + c2.rgba[3], 0.0f, 1.0f)); } Color operator * (float f, const Color& color) { - 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[2]), - clamp(0.0f, 1.0f, f * color.rgba[3])); + return Color(std::clamp(f * color.rgba[0], 0.0f, 1.0f), + std::clamp(f * color.rgba[1], 0.0f, 1.0f), + std::clamp(f * color.rgba[2], 0.0f, 1.0f), + std::clamp(f * color.rgba[3], 0.0f, 1.0f)); } } // namespace Slic3r From 67655743b957fc36f7082133f86bc382f2f1701a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 16:18:35 +0100 Subject: [PATCH 61/85] Follow-up of merge of pull request #3293 -> Fixed missing include (for MAC build) --- src/libslic3r/GCode/PreviewData.cpp | 1 - src/libslic3r/GCode/PreviewData.hpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 15553c7dc..bdc4367a3 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -1,6 +1,5 @@ #include "Analyzer.hpp" #include "PreviewData.hpp" -#include #include #include "Utils.hpp" diff --git a/src/libslic3r/GCode/PreviewData.hpp b/src/libslic3r/GCode/PreviewData.hpp index a023203f1..35bbfa50a 100644 --- a/src/libslic3r/GCode/PreviewData.hpp +++ b/src/libslic3r/GCode/PreviewData.hpp @@ -13,6 +13,8 @@ #include #include +#include + namespace Slic3r { // Represents an RGBA color From 02aa6294494bc491e0a3294a6c301c24c2574297 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 09:36:34 +0100 Subject: [PATCH 62/85] 3DConnexion devices -> Tweak of sensitivity parameters and dependency of translation from zoom factor --- src/slic3r/GUI/Camera.cpp | 11 ++++++----- src/slic3r/GUI/Camera.hpp | 5 ++++- src/slic3r/GUI/Mouse3DController.cpp | 15 ++++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index f2a560c08..c21947d58 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -143,13 +143,14 @@ void Camera::update_zoom(double delta_zoom) void Camera::set_zoom(double zoom) { // Don't allow to zoom too far outside the scene. - double zoom_min = calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]); + double zoom_min = min_zoom(); if (zoom_min > 0.0) - zoom = std::max(zoom, zoom_min * 0.7); + zoom = std::max(zoom, zoom_min); // Don't allow to zoom too close to the scene. - m_zoom = std::min(zoom, 100.0); + m_zoom = std::min(zoom, max_zoom()); } + #if ENABLE_6DOF_CAMERA void Camera::select_view(const std::string& direction) { @@ -457,9 +458,9 @@ void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& p translate_world(center); } -bool Camera::is_looking_downward() const +double Camera::min_zoom() const { - return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; + return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]); } #endif // ENABLE_6DOF_CAMERA diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 87060e288..2a4336108 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -140,7 +140,10 @@ public: void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot); // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis - bool is_looking_downward() const; + bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; } + + double max_zoom() const { return 100.0; } + double min_zoom() const; #endif // ENABLE_6DOF_CAMERA private: diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 6de2c0850..bafb10c52 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -156,7 +156,8 @@ bool Mouse3DController::State::apply(Camera& camera) { const Vec3d& translation = m_translation.queue.front(); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - camera.set_target(camera.get_target() + camera.get_inv_zoom() * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); + double zoom_factor = camera.min_zoom() / camera.get_zoom(); + camera.set_target(camera.get_target() + zoom_factor * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); if (translation(1) != 0.0) camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1))); #else @@ -655,12 +656,12 @@ bool Mouse3DController::connect_device() BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'"; // get device parameters from the config, if present - double translation_speed = 1.0; - float rotation_speed = 1.0; + double translation_speed = 4.0; + float rotation_speed = 4.0; double translation_deadzone = State::DefaultTranslationDeadzone; float rotation_deadzone = State::DefaultRotationDeadzone; #if ENABLE_3DCONNEXION_Y_AS_ZOOM - double zoom_speed = 1.0; + double zoom_speed = 2.0; #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM wxGetApp().app_config->get_mouse_device_translation_speed(m_device_str, translation_speed); wxGetApp().app_config->get_mouse_device_translation_deadzone(m_device_str, translation_deadzone); @@ -670,12 +671,12 @@ bool Mouse3DController::connect_device() wxGetApp().app_config->get_mouse_device_zoom_speed(m_device_str, zoom_speed); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // clamp to valid values - m_state.set_translation_scale(State::DefaultTranslationScale* std::clamp(translation_speed, 0.1, 10.0)); + m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.1, 10.0)); m_state.set_translation_deadzone(std::clamp(translation_deadzone, 0.0, State::MaxTranslationDeadzone)); - m_state.set_rotation_scale(State::DefaultRotationScale* std::clamp(rotation_speed, 0.1f, 10.0f)); + m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f)); m_state.set_rotation_deadzone(std::clamp(rotation_deadzone, 0.0f, State::MaxRotationDeadzone)); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - m_state.set_zoom_scale(State::DefaultZoomScale* std::clamp(zoom_speed, 0.1, 10.0)); + m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0)); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM } #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT From dad09c737c1175e8b6934cda5ae6f49337f8bfe6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 10:34:32 +0100 Subject: [PATCH 63/85] ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE set as default --- src/libslic3r/Technologies.hpp | 3 --- src/slic3r/GUI/GLTexture.cpp | 8 ++++---- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 4 ---- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 10 ---------- 8 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 23c516a34..207fde630 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,9 +44,6 @@ // Enable adaptive layer height profile #define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1) -// Enable grayed variant for gizmos icons in non activable state -#define ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE (1 && ENABLE_2_2_0_ALPHA1) - // Enable fix for view toolbar background not showing up on Mac with dark mode #define ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX (1 && ENABLE_2_2_0_ALPHA1) diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 2834c9603..4ac69d71f 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -276,12 +276,12 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorget_sprite_id(); -#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE int icon_idx = (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3)); -#else - int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0); -#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE #if ENABLE_MODIFIED_TOOLBAR_TEXTURES float v_top = v_offset + sprite_id * dv; @@ -971,9 +963,7 @@ bool GLGizmosManager::generate_icons_texture() const states.push_back(std::make_pair(1, false)); // Activable states.push_back(std::make_pair(0, false)); // Hovered states.push_back(std::make_pair(0, true)); // Selected -#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE states.push_back(std::make_pair(2, false)); // Disabled -#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size(); // // force even size From b6ab6378d771a99ac3e36b8ef132a25f0bb3c459 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 10:50:25 +0100 Subject: [PATCH 64/85] ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX set as default --- src/libslic3r/Technologies.hpp | 3 --- src/slic3r/GUI/GLCanvas3D.cpp | 11 ----------- src/slic3r/GUI/GLCanvas3D.hpp | 5 ----- src/slic3r/GUI/GLToolbar.hpp | 2 -- src/slic3r/GUI/Plater.cpp | 30 ------------------------------ src/slic3r/GUI/Plater.hpp | 2 -- 6 files changed, 53 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 207fde630..4427fe97f 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,9 +44,6 @@ // Enable adaptive layer height profile #define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1) -// Enable fix for view toolbar background not showing up on Mac with dark mode -#define ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX (1 && ENABLE_2_2_0_ALPHA1) - // Enable selection for missing files in reload from disk command #define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1669b3397..c65ca0711 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1349,9 +1349,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const } } -#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX -wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); -#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -1521,10 +1518,6 @@ bool GLCanvas3D::init() if (m_selection.is_enabled() && !m_selection.init()) return false; -#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX - post_event(SimpleEvent(EVT_GLCANVAS_INIT)); -#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX - m_initialized = true; return true; @@ -4233,10 +4226,8 @@ bool GLCanvas3D::_init_toolbars() if (!_init_undoredo_toolbar()) return false; -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX if (!_init_view_toolbar()) return false; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX return true; } @@ -4495,12 +4486,10 @@ bool GLCanvas3D::_init_undoredo_toolbar() return true; } -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool GLCanvas3D::_init_view_toolbar() { return wxGetApp().plater()->init_view_toolbar(); } -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool GLCanvas3D::_set_current() { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e07ccd7fd..6843f7b86 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -83,9 +83,6 @@ template using Vec3dsEvent = ArrayEvent; using HeightProfileSmoothEvent = Event; -#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX -wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); -#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); @@ -683,9 +680,7 @@ private: bool _init_toolbars(); bool _init_main_toolbar(); bool _init_undoredo_toolbar(); -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool _init_view_toolbar(); -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool _set_current(); void _resize(unsigned int w, unsigned int h); diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index bbc773de2..f53b8efb9 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -295,9 +295,7 @@ public: bool is_any_item_pressed() const; -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX unsigned int get_items_count() const { return (unsigned int)m_items.size(); } -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX int get_item_id(const std::string& name) const; void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6f77c1db6..25c359dca 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1857,9 +1857,7 @@ struct Plater::priv void set_current_canvas_as_dirty(); -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool init_view_toolbar(); -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX void reset_all_gizmos(); void update_ui_from_settings(); @@ -2006,9 +2004,6 @@ private: bool complit_init_object_menu(); bool complit_init_sla_object_menu(); bool complit_init_part_menu(); -#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX - void init_view_toolbar(); -#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool can_split() const; bool layers_height_allowed() const; @@ -2160,9 +2155,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this); view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this); view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this); -#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX - view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); }); -#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&) { set_bed_shape(config->option("bed_shape")->values, @@ -3994,17 +3986,11 @@ void Plater::priv::set_current_canvas_as_dirty() preview->set_as_dirty(); } -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool Plater::priv::init_view_toolbar() -#else -void Plater::priv::init_view_toolbar() -#endif //!ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX { -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX if (view_toolbar.get_items_count() > 0) // already initialized return true; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX BackgroundTexture::Metadata background_data; background_data.filename = "toolbar_background.png"; @@ -4014,11 +4000,7 @@ void Plater::priv::init_view_toolbar() background_data.bottom = 16; if (!view_toolbar.init(background_data)) -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX return false; -#else - return; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX view_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Left); view_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Bottom); @@ -4033,11 +4015,7 @@ void Plater::priv::init_view_toolbar() item.sprite_id = 0; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); }; if (!view_toolbar.add_item(item)) -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX return false; -#else - return; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX item.name = "Preview"; item.icon_filename = "preview.svg"; @@ -4045,18 +4023,12 @@ void Plater::priv::init_view_toolbar() item.sprite_id = 1; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); }; if (!view_toolbar.add_item(item)) -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX return false; -#else - return; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX view_toolbar.select_item("3D"); view_toolbar.set_enabled(true); -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX return true; -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX } bool Plater::priv::can_set_instance_to_object() const @@ -5515,12 +5487,10 @@ void Plater::msw_rescale() GetParent()->Layout(); } -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool Plater::init_view_toolbar() { return p->init_view_toolbar(); } -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX const Camera& Plater::get_camera() const { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 479397705..1bea07795 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -266,9 +266,7 @@ public: void msw_rescale(); -#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool init_view_toolbar(); -#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX const Camera& get_camera() const; const Mouse3DController& get_mouse3d_controller() const; From ccb126a5f4e1d9bb34b84ef2f62caeb3cdabfceb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 11:07:10 +0100 Subject: [PATCH 65/85] ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION set as default --- src/libslic3r/Technologies.hpp | 3 --- src/slic3r/GUI/Plater.cpp | 14 -------------- 2 files changed, 17 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4427fe97f..101562a8c 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,9 +44,6 @@ // Enable adaptive layer height profile #define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1) -// Enable selection for missing files in reload from disk command -#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1) - // Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons #define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 25c359dca..852d707a8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3233,12 +3233,9 @@ void Plater::priv::reload_from_disk() // collects paths of files to load std::vector input_paths; -#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION std::vector missing_input_paths; -#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION for (const SelectedVolume& v : selected_volumes) { -#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION const ModelObject* object = model.objects[v.object_idx]; const ModelVolume* volume = object->volumes[v.volume_idx]; @@ -3249,14 +3246,8 @@ void Plater::priv::reload_from_disk() else missing_input_paths.push_back(volume->source.input_file); } -#else - const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx]; - if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file)) - input_paths.push_back(volume->source.input_file); -#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION } -#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION std::sort(missing_input_paths.begin(), missing_input_paths.end()); missing_input_paths.erase(std::unique(missing_input_paths.begin(), missing_input_paths.end()), missing_input_paths.end()); @@ -3306,7 +3297,6 @@ void Plater::priv::reload_from_disk() return; } } -#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION std::sort(input_paths.begin(), input_paths.end()); input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end()); @@ -4093,11 +4083,7 @@ bool Plater::priv::can_reload_from_disk() const for (const SelectedVolume& v : selected_volumes) { const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx]; -#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION if (!volume->source.input_file.empty()) -#else - if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file)) -#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION paths.push_back(volume->source.input_file); } std::sort(paths.begin(), paths.end()); From 4eee7029843b887844370bd7dd3fe30f99b93b2c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 11:26:26 +0100 Subject: [PATCH 66/85] ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE set as default --- src/libslic3r/Slicing.cpp | 12 --- src/libslic3r/Technologies.hpp | 3 - src/slic3r/GUI/GLCanvas3D.cpp | 135 --------------------------------- src/slic3r/GUI/GLCanvas3D.hpp | 31 -------- src/slic3r/GUI/Plater.cpp | 2 - 5 files changed, 183 deletions(-) diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 8199bde03..2a32ba5ef 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -300,26 +300,14 @@ std::vector layer_height_profile_adaptive(const SlicingParameters& slici layer_height_profile.push_back(print_z); layer_height_profile.push_back(height); print_z += height; -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - layer_height_profile.push_back(print_z); - layer_height_profile.push_back(height); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2]; if (z_gap > 0.0) { layer_height_profile.push_back(slicing_params.object_print_z_height()); layer_height_profile.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, z_gap)); } -#else - double last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]); - layer_height_profile.push_back(last); - layer_height_profile.push_back(slicing_params.first_object_layer_height); - layer_height_profile.push_back(slicing_params.object_print_z_height()); - layer_height_profile.push_back(slicing_params.first_object_layer_height); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return layer_height_profile; } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 101562a8c..909cbfd71 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -41,9 +41,6 @@ #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR) -// Enable adaptive layer height profile -#define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1) - // Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons #define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c65ca0711..473026a5d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -132,9 +132,7 @@ GLCanvas3D::LayersEditing::LayersEditing() , m_object_max_z(0.f) , m_slicing_parameters(nullptr) , m_layer_height_profile_modified(false) -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE , m_adaptive_quality(0.5f) -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE , state(Unknown) , band_width(2.0f) , strength(0.005f) @@ -155,9 +153,6 @@ GLCanvas3D::LayersEditing::~LayersEditing() } const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f; -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f; -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename) { @@ -224,7 +219,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const if (!m_enabled) return; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); const Size& cnv_size = canvas.get_canvas_size(); @@ -319,13 +313,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const imgui.end(); const Rect& bar_rect = get_bar_rect_viewport(canvas); -#else - const Rect& bar_rect = get_bar_rect_viewport(canvas); - const Rect& reset_rect = get_reset_rect_viewport(canvas); - - _render_tooltip_texture(canvas, bar_rect, reset_rect); - _render_reset_texture(reset_rect); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE render_active_object_annotations(canvas, bar_rect); render_profile(bar_rect); } @@ -352,38 +339,15 @@ bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, floa return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom()); } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -bool GLCanvas3D::LayersEditing::reset_rect_contains(const GLCanvas3D& canvas, float x, float y) -{ - const Rect& rect = get_reset_rect_screen(canvas); - return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom()); -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) { const Size& cnv_size = canvas.get_canvas_size(); float w = (float)cnv_size.get_width(); float h = (float)cnv_size.get_height(); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return Rect(w - thickness_bar_width(canvas), 0.0f, w, h); -#else - return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas)); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas) -{ - const Size& cnv_size = canvas.get_canvas_size(); - float w = (float)cnv_size.get_width(); - float h = (float)cnv_size.get_height(); - - return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h); -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) { const Size& cnv_size = canvas.get_canvas_size(); @@ -393,27 +357,9 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); -#else - return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas) -{ - const Size& cnv_size = canvas.get_canvas_size(); - float half_w = 0.5f * (float)cnv_size.get_width(); - float half_h = 0.5f * (float)cnv_size.get_height(); - - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - - return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - bool GLCanvas3D::LayersEditing::is_initialized() const { return m_shader.is_initialized(); @@ -448,54 +394,6 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con return ret; } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const -{ - // TODO: do this with ImGui - - if (m_tooltip_texture.get_id() == 0) - { - std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png"; - if (!m_tooltip_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false)) - return; - } - -#if ENABLE_RETINA_GL - const float scale = canvas.get_canvas_size().get_scale_factor(); -#else - const float scale = canvas.get_wxglcanvas()->GetContentScaleFactor(); -#endif - const float width = (float)m_tooltip_texture.get_width() * scale; - const float height = (float)m_tooltip_texture.get_height() * scale; - - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - float gap = 10.0f * inv_zoom; - - float bar_left = bar_rect.get_left(); - float reset_bottom = reset_rect.get_bottom(); - - float l = bar_left - width * inv_zoom - gap; - float r = bar_left - gap; - float t = reset_bottom + height * inv_zoom + gap; - float b = reset_bottom + gap; - - GLTexture::render_texture(m_tooltip_texture.get_id(), l, r, b, t); -} - -void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) const -{ - if (m_reset_texture.get_id() == 0) - { - std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png"; - if (!m_reset_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false)) - return; - } - - GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top()); -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const { m_shader.start_using(); @@ -644,7 +542,6 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas) canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor) { this->update_slicing_parameters(); @@ -662,7 +559,6 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, m_layers_texture.valid = false; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void GLCanvas3D::LayersEditing::generate_layer_height_texture() { @@ -725,19 +621,6 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas) * THICKNESS_BAR_WIDTH; } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas) -{ - return -#if ENABLE_RETINA_GL - canvas.get_canvas_size().get_scale_factor() -#else - canvas.get_wxglcanvas()->GetContentScaleFactor() -#endif - * THICKNESS_RESET_BUTTON_HEIGHT; -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX); const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX); @@ -1372,11 +1255,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent); wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent); wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE #if ENABLE_THUMBNAIL_GENERATOR const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; @@ -1674,7 +1555,6 @@ bool GLCanvas3D::is_layers_editing_allowed() const return m_layers_editing.is_allowed(); } -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void GLCanvas3D::reset_layer_height_profile() { wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Reset"))); @@ -1698,7 +1578,6 @@ void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams& m_layers_editing.state = LayersEditing::Completed; m_dirty = true; } -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool GLCanvas3D::is_reload_delayed() const { @@ -3110,20 +2989,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_layers_editing.state = LayersEditing::Editing; _perform_layer_editing_action(&evt); } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1))) - { - if (evt.LeftDown()) - { - // A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile. - m_layers_editing.reset_layer_height_profile(*this); - // Index 2 means no editing, just wait for mouse up event. - m_layers_editing.state = LayersEditing::Completed; - - m_dirty = true; - } - } -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) { if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 6843f7b86..d4386f7f3 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -105,11 +105,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent); wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent); wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class GLCanvas3D { @@ -159,17 +157,10 @@ private: private: static const float THICKNESS_BAR_WIDTH; -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - static const float THICKNESS_RESET_BUTTON_HEIGHT; -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool m_enabled; Shader m_shader; unsigned int m_z_texture_id; -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - mutable GLTexture m_tooltip_texture; - mutable GLTexture m_reset_texture; -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Not owned by LayersEditing. const DynamicPrintConfig *m_config; // ModelObject for the currently selected object (Model::objects[last_object_id]). @@ -181,10 +172,8 @@ private: std::vector m_layer_height_profile; bool m_layer_height_profile_modified; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE mutable float m_adaptive_quality; mutable HeightProfileSmoothingParams m_smooth_params; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class LayersTexture { @@ -232,24 +221,13 @@ private: void adjust_layer_height_profile(); void accept_changes(GLCanvas3D& canvas); void reset_layer_height_profile(GLCanvas3D& canvas); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor); void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static float get_cursor_z_relative(const GLCanvas3D& canvas); static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_bar_rect_screen(const GLCanvas3D& canvas); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - static Rect get_reset_rect_screen(const GLCanvas3D& canvas); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - static Rect get_reset_rect_viewport(const GLCanvas3D& canvas); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE float object_max_z() const { return m_object_max_z; } @@ -258,18 +236,11 @@ private: private: bool is_initialized() const; void generate_layer_height_texture(); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const; - void _render_reset_texture(const Rect& reset_rect) const; -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const; void render_profile(const Rect& bar_rect) const; void update_slicing_parameters(); static float thickness_bar_width(const GLCanvas3D &canvas); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - static float reset_button_height(const GLCanvas3D &canvas); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE }; struct Mouse @@ -536,11 +507,9 @@ public: bool is_layers_editing_enabled() const; bool is_layers_editing_allowed() const; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void reset_layer_height_profile(); void adaptive_layer_height_profile(float quality_factor); void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool is_reload_delayed() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 852d707a8..69a3f6763 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2137,11 +2137,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); }); view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); }); view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); }); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); }); view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); }); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); From 94a3d38afd8fb6e55292d7b64ba92a6f57fed99c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 11:45:52 +0100 Subject: [PATCH 67/85] ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG set as default --- src/libslic3r/Technologies.hpp | 3 --- src/slic3r/GUI/GLCanvas3D.cpp | 4 ---- src/slic3r/GUI/Mouse3DController.cpp | 22 ---------------------- src/slic3r/GUI/Mouse3DController.hpp | 10 ---------- 4 files changed, 39 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 909cbfd71..4d76c1b2f 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -41,9 +41,6 @@ #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR) -// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons -#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1) - // Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member #define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 473026a5d..bb24d5f12 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1799,11 +1799,7 @@ void GLCanvas3D::render() m_camera.debug_render(); #endif // ENABLE_CAMERA_STATISTICS -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this); -#else - wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG wxGetApp().imgui()->render(); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 8485c4b27..8eee313c0 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -5,9 +5,7 @@ #include "GUI_App.hpp" #include "PresetBundle.hpp" #include "AppConfig.hpp" -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG #include "GLCanvas3D.hpp" -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG #include @@ -200,9 +198,7 @@ Mouse3DController::Mouse3DController() , m_device_str("") , m_running(false) , m_show_settings_dialog(false) -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG , m_settings_dialog_closed_by_user(false) -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG { m_last_time = std::chrono::high_resolution_clock::now(); } @@ -247,9 +243,7 @@ bool Mouse3DController::apply(Camera& camera) disconnect_device(); // hides the settings dialog if the user un-plug the device m_show_settings_dialog = false; -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG m_settings_dialog_closed_by_user = false; -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG } // check if the user plugged the device @@ -259,16 +253,11 @@ bool Mouse3DController::apply(Camera& camera) return is_device_connected() ? m_state.apply(camera) : false; } -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const -#else -void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG { if (!m_running || !m_show_settings_dialog) return; -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG // when the user clicks on [X] or [Close] button we need to trigger // an extra frame to let the dialog disappear if (m_settings_dialog_closed_by_user) @@ -280,16 +269,10 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign } Size cnv_size = canvas.get_canvas_size(); -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG ImGuiWrapper& imgui = *wxGetApp().imgui(); -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f); -#else - imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f); -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG static ImVec2 last_win_size(0.0f, 0.0f); bool shown = true; if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse)) @@ -304,9 +287,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign last_win_size = win_size; canvas.request_extra_frame(); } -#else - imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator); ImGui::PushStyleColor(ImGuiCol_Text, color); @@ -389,7 +369,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign Vec3f target = wxGetApp().plater()->get_camera().get_target().cast(); ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG ImGui::Separator(); if (imgui.button(_(L("Close")))) @@ -406,7 +385,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign canvas.set_as_dirty(); } } -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG imgui.end(); } diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index 1cddf254b..f3826f8e2 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -18,9 +18,7 @@ namespace Slic3r { namespace GUI { struct Camera; -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG class GLCanvas3D; -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG class Mouse3DController { @@ -143,13 +141,9 @@ class Mouse3DController hid_device* m_device; std::string m_device_str; bool m_running; -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG mutable bool m_show_settings_dialog; // set to true when ther user closes the dialog by clicking on [X] or [Close] buttons mutable bool m_settings_dialog_closed_by_user; -#else - bool m_show_settings_dialog; -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG std::chrono::time_point m_last_time; public: @@ -167,11 +161,7 @@ public: bool is_settings_dialog_shown() const { return m_show_settings_dialog; } void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); } -#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG void render_settings_dialog(GLCanvas3D& canvas) const; -#else - void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const; -#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG private: bool connect_device(); From cc19e9c48f36da2484fea8cebb1074fad342f7fa Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 12:12:38 +0100 Subject: [PATCH 68/85] ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE set as default --- src/libslic3r/Format/3mf.cpp | 21 --------------------- src/libslic3r/Format/AMF.cpp | 20 -------------------- src/libslic3r/Model.hpp | 4 ---- src/libslic3r/Technologies.hpp | 3 --- src/slic3r/GUI/Plater.cpp | 10 ---------- 5 files changed, 58 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index ab4848c9a..14177ed88 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1717,9 +1717,6 @@ namespace Slic3r { break; } } -#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE - Transform3d inv_matrix = volume_matrix_to_object.inverse(); -#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE // splits volume out of imported geometry TriangleMesh triangle_mesh; @@ -1739,15 +1736,7 @@ namespace Slic3r { for (unsigned int v = 0; v < 3; ++v) { unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3; -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); -#else - Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); - facet.vertex[v] = has_transform ? - // revert the vertices to the original mesh reference system - (inv_matrix * vertex.cast()).cast() : - vertex; -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } @@ -1755,15 +1744,9 @@ namespace Slic3r { triangle_mesh.repair(); ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE // stores the volume matrix taken from the metadata, if present if (has_transform) volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object); -#else - // apply the volume matrix taken from the metadata, if present - if (has_transform) - volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object)); -#endif //ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE volume->calculate_convex_hull(); // apply the remaining volume's metadata @@ -2567,11 +2550,7 @@ namespace Slic3r { // stores volume's local matrix stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\""; -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix(); -#else - const Transform3d& matrix = volume->get_matrix(); -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index efb90f592..7041956ba 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -585,36 +585,20 @@ void AMFParserContext::endElement(const char * /* name */) stl_allocate(&stl); bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10); -#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE - Transform3d inv_matrix = m_volume_transform.inverse(); -#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE for (size_t i = 0; i < m_volume_facets.size();) { stl_facet &facet = stl.facet_start[i/3]; for (unsigned int v = 0; v < 3; ++v) { unsigned int tri_id = m_volume_facets[i++] * 3; -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); -#else - Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); - facet.vertex[v] = has_transform ? - // revert the vertices to the original mesh reference system - (inv_matrix * vertex.cast()).cast() : - vertex; -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } stl_get_size(&stl); mesh.repair(); m_volume->set_mesh(std::move(mesh)); -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE // stores the volume matrix taken from the metadata, if present if (has_transform) m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform); -#else - if (has_transform) - m_volume->set_transformation(m_volume_transform); -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) { m_volume->source.object_idx = (int)m_model.objects.size() - 1; @@ -1163,11 +1147,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; stream << " "; -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix(); -#else - const Transform3d& matrix = volume->get_matrix(); -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE stream << std::setprecision(std::numeric_limits::max_digits10); for (int r = 0; r < 4; ++r) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 509c70b15..4c1a914c3 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -399,13 +399,9 @@ public: int object_idx{ -1 }; int volume_idx{ -1 }; Vec3d mesh_offset{ Vec3d::Zero() }; -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE Geometry::Transformation transform; template void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset, transform); } -#else - template void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); } -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE }; Source source; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4d76c1b2f..be1fbd001 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -41,9 +41,6 @@ #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR) -// Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member -#define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1) - //================== // 2.2.0.beta1 techs diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 69a3f6763..83570ae74 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3340,27 +3340,17 @@ void Plater::priv::reload_from_disk() new_volume->config.apply(old_volume->config); new_volume->set_type(old_volume->type()); new_volume->set_material_id(old_volume->material_id()); -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE new_volume->set_transformation(old_volume->get_transformation() * old_volume->source.transform); -#else - new_volume->set_transformation(old_volume->get_transformation()); -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->source.input_file = path; std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); -#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE old_model_object->ensure_on_bed(); -#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } } } -#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE - model.adjust_min_z(); -#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE - // update 3D scene update(); From 2259f7b3e8648b408e51d501ebe424a72f13c283 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 17 Jan 2020 11:38:52 +0100 Subject: [PATCH 69/85] Code refactoring to mode comparison --- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- src/libslic3r/GCodeWriter.hpp | 2 +- src/libslic3r/Model.cpp | 2 +- src/libslic3r/Model.hpp | 5 +- src/libslic3r/Print.cpp | 10 +-- src/slic3r/GUI/GLCanvas3D.cpp | 8 +- src/slic3r/GUI/GUI_Preview.cpp | 17 ++-- src/slic3r/GUI/wxExtensions.cpp | 127 ++++++++++++++++++--------- src/slic3r/GUI/wxExtensions.hpp | 44 ++++------ 10 files changed, 126 insertions(+), 93 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7627f581d..bd22c29e5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1738,7 +1738,7 @@ namespace ProcessLayer if (custom_gcode != nullptr) { // Extruder switches are processed by LayerTools, they should be filtered out. - assert(custom_gcode->gcode != ExtruderChangeCode); + assert(custom_gcode->gcode != ToolChangeCode); const std::string &custom_code = custom_gcode->gcode; std::string pause_print_msg; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index fe8c93c9a..3e01e2594 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -478,7 +478,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) for (unsigned int i : lt.extruders) extruder_printing_above[i] = true; // Skip all custom G-codes above this layer and skip all extruder switches. - for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ExtruderChangeCode); ++ custom_gcode_it); + for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ToolChangeCode); ++ custom_gcode_it); if (custom_gcode_it == custom_gcode_per_print_z.gcodes.rend()) // Custom G-codes were processed. break; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 667c1ef95..abeaf0024 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -13,7 +13,7 @@ namespace Slic3r { // Additional Codes which can be set by user using DoubleSlider static constexpr char ColorChangeCode[] = "M600"; static constexpr char PausePrintCode[] = "M601"; -static constexpr char ExtruderChangeCode[] = "tool_change"; +static constexpr char ToolChangeCode[] = "tool_change"; class GCodeWriter { public: diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ead2c95ca..8699eed7f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1847,7 +1847,7 @@ std::vector> custom_tool_changes(const Model &mo { std::vector> custom_tool_changes; for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z.gcodes) - if (custom_gcode.gcode == ExtruderChangeCode) { + if (custom_gcode.gcode == ToolChangeCode) { // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder)); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 4c1a914c3..d7c813113 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -763,8 +763,9 @@ public: double print_z; std::string gcode; - int extruder; // 0 - "gcode" will be applied for whole print - // else - "gcode" will be applied only for "extruder" print + int extruder; // Informative value for ColorChangeCode and ToolChangeCode + // "gcode" == ColorChangeCode => M600 will be applied for "extruder" extruder + // "gcode" == ToolChangeCode => for whole print tool will be switched to "extruder" extruder std::string color; // if gcode is equal to PausePrintCode, // this field is used for save a short message shown on Printer display }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 08e43564f..1cb16b4de 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -493,18 +493,18 @@ static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_ return true; } -// Returns true if va == vb when all CustomGCode items that are not ExtruderChangeCode are ignored. +// Returns true if va == vb when all CustomGCode items that are not ToolChangeCode are ignored. static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector &va, const std::vector &vb) { auto it_a = va.begin(); auto it_b = vb.begin(); while (it_a != va.end() && it_b != vb.end()) { - if (it_a != va.end() && it_a->gcode != ExtruderChangeCode) { + if (it_a != va.end() && it_a->gcode != ToolChangeCode) { // Skip any CustomGCode items, which are not tool changes. ++ it_a; continue; } - if (it_b != vb.end() && it_b->gcode != ExtruderChangeCode) { + if (it_b != vb.end() && it_b->gcode != ToolChangeCode) { // Skip any CustomGCode items, which are not tool changes. ++ it_b; continue; @@ -512,8 +512,8 @@ static bool custom_per_printz_gcodes_tool_changes_differ(const std::vectorgcode == ExtruderChangeCode); - assert(it_b->gcode == ExtruderChangeCode); + assert(it_a->gcode == ToolChangeCode); + assert(it_b->gcode == ToolChangeCode); if (*it_a != *it_b) // The two Tool Changes differ. return true; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index bb24d5f12..ce4908c38 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5263,11 +5263,11 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c const std::string& code = it->gcode; // pause print or custom Gcode if (code == PausePrintCode || - (code != ColorChangeCode && code != ExtruderChangeCode)) + (code != ColorChangeCode && code != ToolChangeCode)) return number_tools()-1; // last color item is a gray color for pause print or custom G-code // change tool (extruder) - if (code == ExtruderChangeCode) + if (code == ToolChangeCode) return get_color_idx_for_tool_change(it, extruder); // change color for current extruder if (code == ColorChangeCode) { @@ -5289,7 +5289,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c return color_idx; } // change tool (extruder) - if (it->gcode == ExtruderChangeCode) + if (it->gcode == ToolChangeCode) return get_color_idx_for_tool_change(it, extruder); } @@ -5333,7 +5333,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c bool is_tool_change = false; while (it_n != color_print_values->begin()) { --it_n; - if (it_n->gcode == ExtruderChangeCode) { + if (it_n->gcode == ToolChangeCode) { is_tool_change = true; if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == extruder)) return get_m600_color_idx(it); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index dda875ced..f7010a503 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -597,7 +597,7 @@ void Preview::create_double_slider() Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { Model& model = wxGetApp().plater()->model(); - model.custom_gcode_per_print_z.gcodes = m_slider->GetTicksValues(); + model.custom_gcode_per_print_z = m_slider->GetTicksValues(); m_schedule_background_process(); update_view_type(false); @@ -666,8 +666,11 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min(); bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max(); - std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; - check_slider_values(ticks_from_model, layers_z); + // Detect and set manipulation mode for double slider + update_double_slider_mode(); + + Model::CustomGCodeInfo &ticks_info_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z; + check_slider_values(ticks_info_from_model.gcodes, layers_z); m_slider->SetSliderValues(layers_z); assert(m_slider->GetMinValue() == 0); @@ -689,13 +692,9 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee } m_slider->SetSelectionSpan(idx_low, idx_high); - m_slider->SetTicksValues(ticks_from_model); + m_slider->SetTicksValues(ticks_info_from_model); - bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); - - m_slider->EnableTickManipulation(color_print_enable); - // Detect and set manipulation mode for double slider - update_double_slider_mode(); + m_slider->EnableTickManipulation(wxGetApp().plater()->printer_technology() == ptFFF); } void Preview::update_double_slider_mode() diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index f2fed3bf7..7689e31cb 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2532,9 +2532,10 @@ double DoubleSlider::get_double_value(const SelectedSlider& selection) } using t_custom_code = Slic3r::Model::CustomGCode; -std::vector DoubleSlider::GetTicksValues() const +Slic3r::Model::CustomGCodeInfo DoubleSlider::GetTicksValues() const { - std::vector values; + Slic3r::Model::CustomGCodeInfo custom_gcode_per_print_z; + std::vector& values = custom_gcode_per_print_z.gcodes; const int val_size = m_values.size(); if (!m_values.empty()) @@ -2544,17 +2545,23 @@ std::vector DoubleSlider::GetTicksValues() const values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color}); } - return values; + custom_gcode_per_print_z.mode = m_mode; + + return custom_gcode_per_print_z; } -void DoubleSlider::SetTicksValues(const std::vector& heights) +void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_gcode_per_print_z) { if (m_values.empty()) + { + m_ticks_mode = m_mode; return; + } const bool was_empty = m_ticks.empty(); m_ticks.clear(); + const std::vector& heights = custom_gcode_per_print_z.gcodes; for (auto h : heights) { auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon()); @@ -2566,7 +2573,9 @@ void DoubleSlider::SetTicksValues(const std::vector& heights) if (!was_empty && m_ticks.empty()) // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(); + + m_ticks_mode = custom_gcode_per_print_z.mode; Refresh(); Update(); @@ -2793,7 +2802,7 @@ void DoubleSlider::draw_ticks(wxDC& dc) dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/); // Draw icon for "Pause print" or "Custom Gcode" - if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ExtruderChangeCode) + if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ToolChangeCode) { wxBitmap icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode"); @@ -2827,7 +2836,7 @@ std::string DoubleSlider::get_color_for_color_change_tick(std::set::c bool is_tool_change = false; while (it_n != m_ticks.begin()) { --it_n; - if (it_n->gcode == Slic3r::ExtruderChangeCode) { + if (it_n->gcode == Slic3r::ToolChangeCode) { is_tool_change = true; if (it_n->extruder == it->extruder) return it->color; @@ -2863,28 +2872,28 @@ void DoubleSlider::draw_colored_band(wxDC& dc) }; // don't color a band for MultiExtruder mode - if (m_ticks.empty() || m_mode == mmMultiExtruder) + if (m_ticks.empty() || m_mode == t_mode::MultiExtruder) { draw_band(dc, GetParent()->GetBackgroundColour(), main_band); return; } - const int default_color_idx = m_mode==mmMultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0; + const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0; draw_band(dc, wxColour(Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band); std::set::const_iterator tick_it = m_ticks.begin(); while (tick_it != m_ticks.end()) { - if ( (m_mode == mmSingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) || - (m_mode == mmMultiAsSingle && (tick_it->gcode == Slic3r::ExtruderChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) + if ( (m_mode == t_mode::SingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) || + (m_mode == t_mode::MultiAsSingle && (tick_it->gcode == Slic3r::ToolChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) { const wxCoord pos = get_position_from_value(tick_it->tick); is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) : main_band.SetBottom(pos - 1); - const std::string clr_str = m_mode == mmSingleExtruder ? tick_it->color : - tick_it->gcode == Slic3r::ExtruderChangeCode ? + const std::string clr_str = m_mode == t_mode::SingleExtruder ? tick_it->color : + tick_it->gcode == Slic3r::ToolChangeCode ? get_color_for_tool_change_tick(tick_it) : get_color_for_color_change_tick(tick_it); @@ -2934,7 +2943,7 @@ void DoubleSlider::draw_revert_icon(wxDC& dc) void DoubleSlider::draw_cog_icon(wxDC& dc) { - if (m_mode != mmMultiExtruder) + if (m_mode != t_mode::MultiExtruder) return; int width, height; @@ -3046,9 +3055,9 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) if (!m_selection) m_selection = ssHigher; m_ticks.clear(); - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(); } - else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == mmMultiExtruder) { + else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == t_mode::MultiExtruder) { // show dialog for set extruder sequence m_edit_extruder_sequence = true; } @@ -3119,17 +3128,17 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; const auto tick_code_it = m_ticks.find(TICK_CODE{tick}); - tooltip = tick_code_it == m_ticks.end() ? (m_mode == mmMultiAsSingle ? + tooltip = tick_code_it == m_ticks.end() ? (m_mode == t_mode::MultiAsSingle ? _(L("For add change extruder use left mouse button click")) : _(L("For add color change use left mouse button click")) ) + "\n" + _(L("For add another code use right mouse button click")) : - tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_mode == mmSingleExtruder ? + tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ? _(L("For Delete color change use left mouse button click\n" "For Edit color use right mouse button click")) : from_u8((boost::format(_utf8(L("Delete color change for Extruder %1%"))) % tick_code_it->extruder).str()) ): tick_code_it->gcode == Slic3r::PausePrintCode ? _(L("Delete pause")) : - tick_code_it->gcode == Slic3r::ExtruderChangeCode ? + tick_code_it->gcode == Slic3r::ToolChangeCode ? from_u8((boost::format(_utf8(L("Delete extruder change to \"%1%\""))) % tick_code_it->extruder).str()) : from_u8((boost::format(_utf8(L("For Delete \"%1%\" code use left mouse button click\n" "For Edit \"%1%\" code use right mouse button click"))) % tick_code_it->gcode ).str()); @@ -3200,7 +3209,7 @@ void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu) const wxString item_name = wxString::Format(_(L("Extruder %d")), i) + (is_active_extruder ? " (" + _(L("active")) + ")" : ""); - if (m_mode == mmMultiAsSingle) + if (m_mode == t_mode::MultiAsSingle) append_menu_item(change_extruder_menu, wxID_ANY, item_name, "", [this, i](wxCommandEvent&) { change_extruder(i); }, "", menu, [is_active_extruder]() { return !is_active_extruder; }, Slic3r::GUI::wxGetApp().plater()); @@ -3208,13 +3217,13 @@ void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu) // [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder); } - const wxString change_extruder_menu_name = m_mode == mmMultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); + const wxString change_extruder_menu_name = m_mode == t_mode::MultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, "change_extruder")); Slic3r::GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) { - enable_menu_item(evt, [this]() {return m_mode == mmMultiAsSingle; }, change_extruder_menu_item, this); }, + enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); }, change_extruder_menu_item->GetId()); } } @@ -3255,13 +3264,13 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) if (m_show_context_menu) { - if (m_mode == mmSingleExtruder) + if (m_mode == t_mode::SingleExtruder) add_code(Slic3r::ColorChangeCode); else { wxMenu menu; - if (m_mode == mmMultiAsSingle) + if (m_mode == t_mode::MultiAsSingle) append_change_extruder_menu_item(&menu); else append_add_color_change_menu_item(&menu); @@ -3335,7 +3344,7 @@ void DoubleSlider::action_tick(const TicksAction action) return; m_ticks.erase(TICK_CODE{tick}); - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(it->gcode); Refresh(); Update(); return; @@ -3350,7 +3359,7 @@ void DoubleSlider::action_tick(const TicksAction action) if (m_suppress_add_code) return; m_suppress_add_code = true; - if (m_mode == mmSingleExtruder) // if (m_mode != mmMultiExtruder) + if (m_mode == t_mode::SingleExtruder) // if (m_mode != t_mode::MultiExtruder) add_code(Slic3r::ColorChangeCode); m_suppress_add_code = false; return; @@ -3444,7 +3453,7 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) m_show_context_menu = true; return; } - if (it->gcode != Slic3r::ExtruderChangeCode) + if (it->gcode != Slic3r::ToolChangeCode) { // show "Edit" and "Delete" menu on OnRightUp() m_show_edit_menu = true; @@ -3471,14 +3480,14 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) int DoubleSlider::get_extruder_for_tick(int tick) { - int default_initial_extruder = m_mode == mmMultiAsSingle ? m_only_extruder : 0; + int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? m_only_extruder : 0; if (m_ticks.empty()) return default_initial_extruder; auto it = m_ticks.lower_bound(TICK_CODE{tick}); while (it != m_ticks.begin()) { --it; - if(it->gcode == Slic3r::ExtruderChangeCode) + if(it->gcode == Slic3r::ToolChangeCode) return it->extruder; } @@ -3487,7 +3496,7 @@ int DoubleSlider::get_extruder_for_tick(int tick) std::set DoubleSlider::get_used_extruders_for_tick(int tick) { - if (m_mode == mmMultiExtruder) + if (m_mode == t_mode::MultiExtruder) { // #ys_FIXME: get tool ordering from _correct_ place const Slic3r::ToolOrdering& tool_ordering = Slic3r::GUI::wxGetApp().plater()->fff_print().get_tool_ordering(); @@ -3508,7 +3517,7 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) return used_extruders; } - const int default_initial_extruder = m_mode == mmMultiAsSingle ? std::max(m_only_extruder, 1) : 1; + const int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? std::max(m_only_extruder, 1) : 1; if (m_ticks.empty()) return {default_initial_extruder}; @@ -3516,7 +3525,7 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) auto it_start = m_ticks.lower_bound(TICK_CODE{tick}); auto it = it_start; - if (it == m_ticks.begin() && it->gcode == Slic3r::ExtruderChangeCode) { + if (it == m_ticks.begin() && it->gcode == Slic3r::ToolChangeCode) { used_extruders.emplace(it->extruder); if (tick < it->tick) used_extruders.emplace(default_initial_extruder); @@ -3524,7 +3533,7 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) while (it != m_ticks.begin()) { --it; - if(it->gcode == Slic3r::ExtruderChangeCode) + if(it->gcode == Slic3r::ToolChangeCode) { used_extruders.emplace(it->extruder); break; @@ -3536,7 +3545,7 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) it = it_start; while (it != m_ticks.end()) { - if(it->gcode == Slic3r::ExtruderChangeCode) + if(it->gcode == Slic3r::ToolChangeCode) used_extruders.emplace(it->extruder); ++it; } @@ -3554,7 +3563,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) if (m_show_context_menu) { wxMenu menu; - if (m_mode == mmSingleExtruder) + if (m_mode == t_mode::SingleExtruder) append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu, [](){return true;}, this); @@ -3703,7 +3712,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) m_ticks.emplace(TICK_CODE{tick, code, extruder, color}); - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(code); Refresh(); Update(); } @@ -3741,7 +3750,7 @@ void DoubleSlider::edit_tick() m_ticks.erase(it); m_ticks.emplace(changed_tick); - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(changed_tick.gcode); } } @@ -3754,9 +3763,9 @@ void DoubleSlider::change_extruder(int extruder) // if on this Y doesn't exist tick if (m_ticks.find(TICK_CODE{tick}) == m_ticks.end()) { - m_ticks.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); + m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + post_ticks_changed_event(Slic3r::ToolChangeCode); Refresh(); Update(); } @@ -3776,7 +3785,7 @@ void DoubleSlider::edit_extruder_sequence() auto it = m_ticks.begin(); while (it != m_ticks.end()) { - if (it->gcode == Slic3r::ExtruderChangeCode) + if (it->gcode == Slic3r::ToolChangeCode) it = m_ticks.erase(it); else ++it; @@ -3792,7 +3801,7 @@ void DoubleSlider::edit_extruder_sequence() while (tick <= m_max_value) { int cur_extruder = m_extruders_sequence.extruders[extruder]; - m_ticks.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]}); + m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]}); extruder++; if (extruder == extr_cnt) @@ -3811,6 +3820,42 @@ void DoubleSlider::edit_extruder_sequence() tick += m_extruders_sequence.interval_by_layers; } + post_ticks_changed_event(Slic3r::ToolChangeCode); +} + +void DoubleSlider::post_ticks_changed_event(const std::string& gcode /*= ""*/) +{ + if ( m_ticks_mode == m_mode || + (gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) ) + { + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + return; + } + + if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle) + { + } + + if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder) + { + } + + if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::SingleExtruder) + { + } + + if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::MultiExtruder) + { + } + + if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) + { + } + + if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle) + { + } + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 81f4d7342..5b9f6db0b 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -782,6 +782,8 @@ public: const wxString& name = wxEmptyString); ~DoubleSlider() {} + using t_mode = Slic3r::Model::CustomGCodeInfo::MODE; + /* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values. * So, let use same value as a permissible error for layer height. */ @@ -805,37 +807,22 @@ public: // Set low and high slider position. If the span is non-empty, disable the "one layer" mode. void SetSelectionSpan(const int lower_val, const int higher_val); void SetMaxValue(const int max_value); - void SetKoefForLabels(const double koef) { - m_label_koef = koef; - } - void SetSliderValues(const std::vector& values) { - m_values = values; - } + void SetKoefForLabels(const double koef) { m_label_koef = koef; } + void SetSliderValues(const std::vector& values) { m_values = values; } void ChangeOneLayerLock(); - std::vector GetTicksValues() const; - void SetTicksValues(const std::vector &heights); - void EnableTickManipulation(bool enable = true) { - m_is_enabled_tick_manipulation = enable; - } - void DisableTickManipulation() { - EnableTickManipulation(false); - } + Slic3r::Model::CustomGCodeInfo GetTicksValues() const; + void SetTicksValues(const Slic3r::Model::CustomGCodeInfo &custom_gcode_per_print_z); + void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; } + void DisableTickManipulation() { EnableTickManipulation(false); } - enum ManipulationMode { - mmSingleExtruder, // single extruder printer preset is selected - mmMultiAsSingle, // multiple extruder printer preset is selected, but - // this mode works just for Single extruder print - // (For all print from objects settings is used just one extruder) - mmMultiExtruder // multiple extruder printer preset is selected - }; - void SetManipulationMode(ManipulationMode mode) { m_mode = mode; } - ManipulationMode GetManipulationMode() const { return m_mode; } + void SetManipulationMode(t_mode mode) { m_mode = mode; } + t_mode GetManipulationMode() const { return m_mode; } void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder) { - m_mode = !is_one_extruder_printed_model ? mmMultiExtruder : - only_extruder < 0 ? mmSingleExtruder : - mmMultiAsSingle; + m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder : + only_extruder < 0 ? t_mode::SingleExtruder : + t_mode::MultiAsSingle; m_only_extruder = only_extruder; } @@ -918,7 +905,7 @@ private: int get_extruder_for_tick(int tick); std::set get_used_extruders_for_tick(int tick); - + void post_ticks_changed_event(const std::string& gcode = ""); void append_change_extruder_menu_item(wxMenu*); void append_add_color_change_menu_item(wxMenu*); @@ -952,7 +939,7 @@ private: bool m_show_edit_menu = false; bool m_edit_extruder_sequence = false; bool m_suppress_add_code = false; - ManipulationMode m_mode = mmSingleExtruder; + t_mode m_mode = t_mode::SingleExtruder; std::string m_custom_gcode = ""; std::string m_pause_print_msg; int m_only_extruder = -1; @@ -986,6 +973,7 @@ private: std::vector m_segm_pens; std::vector m_values; std::set m_ticks; + t_mode m_ticks_mode; public: struct ExtrudersSequence From cbe5132832f7717ac67f8b2b886c486cde38e40c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 20 Jan 2020 10:38:01 +0100 Subject: [PATCH 70/85] #3540 - Fixed toolpaths preview for empty ranges --- src/libslic3r/GCode/PreviewData.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index bdc4367a3..eecabe718 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -70,19 +70,15 @@ float GCodePreviewData::RangeBase::step_size() const Color GCodePreviewData::RangeBase::get_color_at(float value) const { - if (empty()) - return Color{}; - // Input value scaled to the color range - const float global_t = std::max(0.0f, value - min()) / step_size(); // lower limit of 0.0f - + float step = step_size(); + const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step_size() : 0.0f; // lower limit of 0.0f + constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1; // Compute the two colors just below (low) and above (high) the input value const std::size_t color_low_idx = std::clamp(static_cast(global_t), std::size_t{ 0 }, color_max_idx); const std::size_t color_high_idx = std::clamp(color_low_idx + 1, std::size_t{ 0 }, color_max_idx); - const Color color_low = range_rainbow_colors[color_low_idx]; - const Color color_high = range_rainbow_colors[color_high_idx]; // Compute how far the value is between the low and high colors so that they can be interpolated const float local_t = std::min(global_t - static_cast(color_low_idx), 1.0f); // upper limit of 1.0f @@ -91,7 +87,7 @@ Color GCodePreviewData::RangeBase::get_color_at(float value) const Color ret; for (unsigned int i = 0; i < 4; ++i) { - ret.rgba[i] = lerp(color_low.rgba[i], color_high.rgba[i], local_t); + ret.rgba[i] = lerp(range_rainbow_colors[color_low_idx].rgba[i], range_rainbow_colors[color_high_idx].rgba[i], local_t); } return ret; } @@ -378,11 +374,20 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: list.reserve(range_rainbow_colors.size()); float step = range.step_size(); - for (int i = static_cast(range_rainbow_colors.size()) - 1; i >= 0; --i) + if (step == 0.0f) { char buf[1024]; - sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step)); - list.emplace_back(buf, range_rainbow_colors[i]); + sprintf(buf, "%.*f", decimals, scale_factor * range.min()); + list.emplace_back(buf, range_rainbow_colors[0]); + } + else + { + for (int i = static_cast(range_rainbow_colors.size()) - 1; i >= 0; --i) + { + char buf[1024]; + sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step)); + list.emplace_back(buf, range_rainbow_colors[i]); + } } } }; From c87e951da55c9bc58e9431213ea780233c2565f8 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 20 Jan 2020 13:29:59 +0100 Subject: [PATCH 71/85] #3536 - Fixed PrusaSlicer not closing the file when trying to open an invalid 3mf (actually any zip) file --- src/libslic3r/miniz_extension.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/miniz_extension.cpp b/src/libslic3r/miniz_extension.cpp index e87b1a552..17cc136fc 100644 --- a/src/libslic3r/miniz_extension.cpp +++ b/src/libslic3r/miniz_extension.cpp @@ -26,8 +26,20 @@ bool open_zip(mz_zip_archive *zip, const char *fname, bool isread) return false; } - return isread ? mz_zip_reader_init_cfile(zip, f, 0, 0) - : mz_zip_writer_init_cfile(zip, f, 0); + bool res = false; + if (isread) + { + res = mz_zip_reader_init_cfile(zip, f, 0, 0); + if (!res) + // if we get here it means we tried to open a non-zip file + // we need to close the file here because the call to mz_zip_get_cfile() made into close_zip() returns a null pointer + // see: https://github.com/prusa3d/PrusaSlicer/issues/3536 + fclose(f); + } + else + res = mz_zip_writer_init_cfile(zip, f, 0); + + return res; } bool close_zip(mz_zip_archive *zip, bool isread) From 5fe537836771cdd987c9c976374c3e91a3bb6c52 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 20 Jan 2020 16:57:40 +0100 Subject: [PATCH 72/85] Fixed AstroBox upload type selection. --- src/libslic3r/PrintConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 761507a2e..9fe50d82e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1337,7 +1337,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back("OctoPrint"); def->enum_labels.push_back("Duet"); def->enum_labels.push_back("FlashAir"); - def->enum_values.push_back("AstroBox"); + def->enum_labels.push_back("AstroBox"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(htOctoPrint)); From 290bc4f516b547f53a6defb332e38b65bf9d5e58 Mon Sep 17 00:00:00 2001 From: vintagepc Date: Fri, 10 Jan 2020 21:17:59 -0500 Subject: [PATCH 73/85] Added directory support to FlashAir upload --- src/slic3r/Utils/FlashAir.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index 79f3f2c2b..25ffbc774 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -79,7 +79,7 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); - + //const auto upload_set_dir = upload_da wxString test_msg; if (! test(test_msg)) { error_fn(std::move(test_msg)); @@ -88,7 +88,14 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error bool res = false; + std::string strDest = upload_parent_path.string(); + if (strDest.front()!='/') // Needs a leading / else root uploads fail. + { + strDest.insert(0,"/"); + } + auto urlPrepare = make_url("upload.cgi", "WRITEPROTECT=ON&FTIME", timestamp_str()); + auto urlSetDir = make_url("upload.cgi","UPDIR",strDest); auto urlUpload = make_url("upload.cgi"); BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3% / %4%, filename: %5%") @@ -101,7 +108,7 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error // set filetime for upload and make card writeprotect to prevent filesystem damage auto httpPrepare = Http::get(std::move(urlPrepare)); httpPrepare.on_error([&](std::string body, std::string error, unsigned status) { - BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error prepareing upload: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error preparing upload: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; error_fn(format_error(body, error, status)); res = false; }) @@ -120,6 +127,26 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error } // start file upload + auto httpDir = Http::get(std::move(urlSetDir)); + httpDir.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error setting upload dir: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; + error_fn(format_error(body, error, status)); + res = false; + }) + .on_complete([&, this](std::string body, unsigned) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got dir select result: %2%") % name % body; + res = boost::icontains(body, "SUCCESS"); + if (! res) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Request completed but no SUCCESS message was received.") % name; + error_fn(format_error(body, L("Unknown error occured"), 0)); + } + }) + .perform_sync(); + + if(! res ) { + return res; + } + auto http = Http::post(std::move(urlUpload)); http.form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { From 9f65b6bc96f1584d8034d10e66dd109662a310b9 Mon Sep 17 00:00:00 2001 From: vintagepc Date: Fri, 10 Jan 2020 21:22:23 -0500 Subject: [PATCH 74/85] Removed stray comment --- src/slic3r/Utils/FlashAir.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index 25ffbc774..735e4a70a 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -79,7 +79,6 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); - //const auto upload_set_dir = upload_da wxString test_msg; if (! test(test_msg)) { error_fn(std::move(test_msg)); From 07d6fd8f7ec84d1077752f676827aa774224d1f8 Mon Sep 17 00:00:00 2001 From: foxox Date: Mon, 2 Dec 2019 22:48:01 -0500 Subject: [PATCH 75/85] Platter->Plater --- src/libslic3r/Model.cpp | 2 +- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 8 +++--- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 4 +-- src/slic3r/GUI/MainFrame.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 28 ++++++++++----------- src/slic3r/GUI/Preset.cpp | 2 +- src/slic3r/GUI/Preset.hpp | 4 +-- src/slic3r/GUI/PresetBundle.cpp | 2 +- src/slic3r/GUI/PresetBundle.hpp | 4 +-- src/slic3r/GUI/Tab.cpp | 6 ++--- src/slic3r/GUI/Tab.hpp | 2 +- 13 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8699eed7f..d5a40e79f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -843,7 +843,7 @@ TriangleMesh ModelObject::mesh() const } // Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. -// Currently used by ModelObject::mesh(), to calculate the 2D envelope for 2D platter +// Currently used by ModelObject::mesh(), to calculate the 2D envelope for 2D plater // and to display the object statistics at ModelObject::print_info(). TriangleMesh ModelObject::raw_mesh() const { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d7c813113..fa5d8f155 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -236,7 +236,7 @@ public: // A mesh containing all transformed instances of this object. TriangleMesh mesh() const; // Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. - // Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter. + // Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D plater. TriangleMesh raw_mesh() const; // Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. TriangleMesh full_raw_mesh() const; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 984686e35..c8ece38f0 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -53,11 +53,11 @@ public: void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; } #endif // ENABLE_THUMBNAIL_GENERATOR - // The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished + // The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished // and the background processing will transition into G-code export. // The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed. void set_slicing_completed_event(int event_id) { m_event_slicing_completed_id = event_id; } - // The following wxCommandEvent will be sent to the UI thread / Platter window, when the G-code export is finished. + // The following wxCommandEvent will be sent to the UI thread / Plater window, when the G-code export is finished. // The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed. void set_finished_event(int event_id) { m_event_finished_id = event_id; } @@ -186,9 +186,9 @@ private: void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); } void prepare_upload(); - // wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue. + // wxWidgets command ID to be sent to the plater to inform that the slicing is finished, and the G-code export will continue. int m_event_slicing_completed_id = 0; - // wxWidgets command ID to be sent to the platter to inform that the task finished. + // wxWidgets command ID to be sent to the plater to inform that the task finished. int m_event_finished_id = 0; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 31822354f..e639e3d89 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -555,7 +555,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) update_data(); wxGetApp().obj_manipul()->set_dirty(); - // Let the platter know that the dragging finished, so a delayed refresh + // Let the plater know that the dragging finished, so a delayed refresh // of the scene with the background processing data should be performed. m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); // updates camera target constraints diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2b7fc3740..9fc74bcb8 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -124,7 +124,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S _3DScene::remove_all_canvases(); // Slic3r::GUI::deregister_on_request_update_callback(); - // set to null tabs and a platter + // set to null tabs and a plater // to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing wxGetApp().tabs_list.clear(); wxGetApp().plater_ = nullptr; @@ -1006,7 +1006,7 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re } // Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset. -// Also update the platter with the new presets. +// Also update the plater with the new presets. void MainFrame::load_config(const DynamicPrintConfig& config) { PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 28bd0242b..7b93e70cb 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -125,7 +125,7 @@ public: void load_config(const DynamicPrintConfig& config); void select_tab(size_t tab) const; void select_view(const std::string& direction); - // Propagate changed configuration from the Tab to the Platter and save changes to the AppConfig + // Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig void on_config_changed(DynamicPrintConfig* cfg) const ; void add_to_recent_projects(const wxString& filename); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 83570ae74..25ce50c7b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -323,7 +323,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * cfg_new.set_key_value("extruder_colour", colors); wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new); - wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this); + wxGetApp().preset_bundle->update_plater_filament_ui(extruder_idx, this); wxGetApp().plater()->on_config_change(cfg_new); } }); @@ -949,18 +949,18 @@ void Sidebar::update_all_preset_comboboxes() // Update the print choosers to only contain the compatible presets, update the dirty flags. if (print_tech == ptFFF) - preset_bundle.prints.update_platter_ui(p->combo_print); + preset_bundle.prints.update_plater_ui(p->combo_print); else { - preset_bundle.sla_prints.update_platter_ui(p->combo_sla_print); - preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); + preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print); + preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material); } // Update the printer choosers, update the dirty flags. - preset_bundle.printers.update_platter_ui(p->combo_printer); + preset_bundle.printers.update_plater_ui(p->combo_printer); // Update the filament choosers to only contain the compatible presets, update the color preview, // update the dirty flags. if (print_tech == ptFFF) { for (size_t i = 0; i < p->combos_filament.size(); ++i) - preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); + preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]); } } @@ -983,22 +983,22 @@ void Sidebar::update_presets(Preset::Type preset_type) } for (size_t i = 0; i < filament_cnt; i++) { - preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); + preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]); } break; } case Preset::TYPE_PRINT: - preset_bundle.prints.update_platter_ui(p->combo_print); + preset_bundle.prints.update_plater_ui(p->combo_print); break; case Preset::TYPE_SLA_PRINT: - preset_bundle.sla_prints.update_platter_ui(p->combo_sla_print); + preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print); break; case Preset::TYPE_SLA_MATERIAL: - preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); + preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material); break; case Preset::TYPE_PRINTER: @@ -2072,7 +2072,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) background_process.set_finished_event(EVT_PROCESS_COMPLETED); // Default printer technology for default config. background_process.select_technology(this->printer_technology); - // Register progress callback from the Print class to the Platter. + // Register progress callback from the Print class to the Plater. auto statuscb = [this](const Slic3r::PrintBase::SlicingStatus &status) { wxQueueEvent(this->q, new Slic3r::SlicingStatusEvent(EVT_SLICING_UPDATE, 0, status)); @@ -3473,8 +3473,8 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) // TODO: ? if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) { - // Only update the platter UI for the 2nd and other filaments. - wxGetApp().preset_bundle->update_platter_filament_ui(idx, combo); + // Only update the plater UI for the 2nd and other filaments. + wxGetApp().preset_bundle->update_plater_filament_ui(idx, combo); } else { wxWindowUpdateLocker noUpdates(sidebar->presets_panel()); @@ -5128,7 +5128,7 @@ void Plater::on_extruders_change(size_t num_extruders) choices.push_back(choice); // initialize selection - wxGetApp().preset_bundle->update_platter_filament_ui(i, choice); + wxGetApp().preset_bundle->update_plater_filament_ui(i, choice); ++i; } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index b89000891..797fa28f8 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -1026,7 +1026,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil // Update the wxChoice UI component from this list of presets. // Hide the -void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui) +void PresetCollection::update_plater_ui(GUI::PresetComboBox *ui) { if (ui == nullptr) return; diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 0a26f90cc..742d3e01d 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -442,7 +442,7 @@ public: // Update the choice UI from the list of presets. // Only the compatible presets are shown. // If an incompatible preset is selected, it is shown as well. - void update_platter_ui(GUI::PresetComboBox *ui); + void update_plater_ui(GUI::PresetComboBox *ui); // Update a dirty floag of the current preset, update the labels of the UI component accordingly. // Return true if the dirty flag changed. @@ -531,7 +531,7 @@ private: // Is the "- default -" preset suppressed? bool m_default_suppressed = true; size_t m_num_default_presets = 0; - // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter. + // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Plater. // These bitmaps are not owned by PresetCollection, but by a PresetBundle. const wxBitmap *m_bitmap_compatible = nullptr; const wxBitmap *m_bitmap_incompatible = nullptr; diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 8f5d58bc1..bb08ce2d0 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -1572,7 +1572,7 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window) this->load_compatible_bitmaps(window); } -void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) +void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) { if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA || this->filament_presets.size() <= idx_extruder ) diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 5205042c5..ff27d0023 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -109,8 +109,8 @@ public: // Export a config bundle file containing all the presets and the names of the active presets. void export_configbundle(const std::string &path, bool export_system_settings = false); - // Update a filament selection combo box on the platter for an idx_extruder. - void update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui); + // Update a filament selection combo box on the plater for an idx_extruder. + void update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui); // Enable / disable the "- default -" preset. void set_default_suppressed(bool default_suppressed); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c518ede80..bd0d7b81f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -905,7 +905,7 @@ void Tab::update_wiping_button_visibility() { } -// Call a callback to update the selection of presets on the platter: +// Call a callback to update the selection of presets on the plater: // To update the content of the selection boxes, // to update the filament colors of the selection boxes, // to update the "dirty" flags of the selection boxes, @@ -2825,7 +2825,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current) if (canceled) { update_tab_ui(); // Trigger the on_presets_changed event so that we also restore the previous value in the plater selector, - // if this action was initiated from the platter. + // if this action was initiated from the plater. on_presets_changed(); } else { if (current_dirty) @@ -3053,7 +3053,7 @@ void Tab::save_preset(std::string name /*= ""*/) m_preset_bundle->update_compatible(false); // Add the new item into the UI component, remove dirty flags and activate the saved item. update_tab_ui(); - // Update the selection boxes at the platter. + // Update the selection boxes at the plater. on_presets_changed(); // If current profile is saved, "delete preset" button have to be enabled m_btn_delete_preset->Enable(true); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index ee6937652..4345f196c 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -231,7 +231,7 @@ public: // Counter for the updating (because of an update() function can have a recursive behavior): // 1. increase value from the very beginning of an update() function // 2. decrease value at the end of an update() function - // 3. propagate changed configuration to the Platter when (m_update_cnt == 0) only + // 3. propagate changed configuration to the Plater when (m_update_cnt == 0) only int m_update_cnt = 0; public: From b616c16c0a2755ddd2e0b45ac9f063e31d2f0ed3 Mon Sep 17 00:00:00 2001 From: Jebtrix Date: Wed, 28 Aug 2019 19:29:44 -0400 Subject: [PATCH 76/85] Change confusing message text --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 25ce50c7b..b388ad1d2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2348,7 +2348,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (object->volumes.size() > 1) { Slic3r::GUI::show_info(nullptr, - _(L("You can't load SLA project if there is at least one multi-part object on the bed")) + "\n\n" + + _(L("You cannot load SLA project with a multi-part object on the bed")) + "\n\n" + _(L("Please check your object list before preset changing.")), _(L("Attention!"))); return obj_idxs; From 1779fc0e1d224186d4d95ef5bc1cdd023956ea5c Mon Sep 17 00:00:00 2001 From: Jebtrix Date: Wed, 28 Aug 2019 19:39:40 -0400 Subject: [PATCH 77/85] Change confusing message text --- resources/localization/PrusaSlicer.pot | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/localization/PrusaSlicer.pot b/resources/localization/PrusaSlicer.pot index 13f55f7bb..c5bcaa3bd 100644 --- a/resources/localization/PrusaSlicer.pot +++ b/resources/localization/PrusaSlicer.pot @@ -3622,8 +3622,7 @@ msgstr "" #: src/slic3r/GUI/Plater.cpp:2315 msgid "" -"You can't load SLA project if there is at least one multi-part object on the " -"bed" +"You cannot load SLA project with a multi-part object on the bed" msgstr "" #: src/slic3r/GUI/Plater.cpp:2316 src/slic3r/GUI/Tab.cpp:2915 From 5342ad899022782093616ca610747456b70dbf0c Mon Sep 17 00:00:00 2001 From: Jebtrix Date: Mon, 4 Nov 2019 15:48:55 -0500 Subject: [PATCH 78/85] Fix [scale] from being assigned to [year] placeholder [year] in output filename format results in blank file name (Issue #2349) --- src/libslic3r/PrintBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index fdee67f2e..55e24178d 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -37,7 +37,7 @@ void PrintBase::update_object_placeholders(DynamicConfig &config, const std::str } } - config.set_key_value("year", new ConfigOptionStrings(v_scale)); + config.set_key_value("scale", new ConfigOptionStrings(v_scale)); if (! input_file.empty()) { // get basename with and without suffix const std::string input_filename = boost::filesystem::path(input_file).filename().string(); From 7efca35c277bee219cb298c3fa0d19c494c8c73f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 21 Jan 2020 09:55:36 +0100 Subject: [PATCH 79/85] Don't store "print_host", "printhost_apikey", "printhost_cafile" into the G-code. --- src/libslic3r/GCode.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bd22c29e5..517b5281b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,8 @@ #include "miniz_extension.hpp" +using namespace std::literals::string_view_literals; + #if 0 // Enable debugging and asserts, even in the release build. #define DEBUG @@ -2268,8 +2271,20 @@ void GCode::apply_print_config(const PrintConfig &print_config) void GCode::append_full_config(const Print &print, std::string &str) { const DynamicPrintConfig &cfg = print.full_print_config(); + // Sorted list of config keys, which shall not be stored into the G-code. Initializer list. + static constexpr auto banned_keys = { + "compatible_printers"sv, + "compatible_prints"sv, + "print_host"sv, + "printhost_apikey"sv, + "printhost_cafile"sv + }; + assert(std::is_sorted(banned_keys.begin(), banned_keys.end())); + auto is_banned = [](const std::string &key) { + return std::binary_search(banned_keys.begin(), banned_keys.end(), key); + }; for (const std::string &key : cfg.keys()) - if (key != "compatible_prints" && key != "compatible_printers" && ! cfg.option(key)->is_nil()) + if (! is_banned(key) && ! cfg.option(key)->is_nil()) str += "; " + key + " = " + cfg.opt_serialize(key) + "\n"; } From d8325cfc06370e7383e622405ab40345b3df30c9 Mon Sep 17 00:00:00 2001 From: Italo Soares Date: Sat, 21 Dec 2019 20:10:07 -0300 Subject: [PATCH 80/85] Fixed some translations for better understanding --- .../localization/pt_br/PrusaSlicer_pt_br.po | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/resources/localization/pt_br/PrusaSlicer_pt_br.po b/resources/localization/pt_br/PrusaSlicer_pt_br.po index e54f17ec3..647a9dd4f 100644 --- a/resources/localization/pt_br/PrusaSlicer_pt_br.po +++ b/resources/localization/pt_br/PrusaSlicer_pt_br.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-09-09 16:39+0200\n" -"PO-Revision-Date: 2019-11-18 16:39-0300\n" +"PO-Revision-Date: 2019-12-21 19:55-0300\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1432,7 +1432,7 @@ msgid "" "You will lose content of the plater." msgstr "" "Alterar a linguagem fará com que o aplicativo reinicie.\n" -"Você irá perder conteúdo no prato." +"Você irá perder conteúdo na bandeja." #: src/slic3r/GUI/GUI_App.cpp:877 msgid "Do you want to proceed?" @@ -2302,7 +2302,7 @@ msgstr "(Re)fatiar" #: src/slic3r/GUI/KBShortcutsDialog.cpp:116 msgid "Select Plater Tab" -msgstr "Selecione a guia de prato" +msgstr "Selecione a guia de bandeja" #: src/slic3r/GUI/KBShortcutsDialog.cpp:118 msgid "Select Print Settings Tab" @@ -2466,7 +2466,7 @@ msgstr "Desmarcar Gizmo/limpar seleção" #: src/slic3r/GUI/KBShortcutsDialog.cpp:166 msgid "Plater Shortcuts" -msgstr "Atalhos do prato" +msgstr "Atalhos da bandeja" #: src/slic3r/GUI/KBShortcutsDialog.cpp:181 #: src/slic3r/GUI/KBShortcutsDialog.cpp:193 @@ -2546,7 +2546,7 @@ msgstr "baseado no Slic3r" #: src/slic3r/GUI/MainFrame.cpp:189 msgid "Plater" -msgstr "Prato" +msgstr "Bandeja" #: src/slic3r/GUI/MainFrame.cpp:400 msgid "&New Project" @@ -2635,7 +2635,7 @@ msgstr "Exportar &G-code" #: src/slic3r/GUI/MainFrame.cpp:469 msgid "Export current plate as G-code" -msgstr "Exporte o prato atual como o G-code" +msgstr "Exporte a bandeja atual como o G-code" #: src/slic3r/GUI/MainFrame.cpp:473 src/slic3r/GUI/MainFrame.cpp:720 msgid "S&end G-code" @@ -2643,31 +2643,31 @@ msgstr "E&nviar G-code" #: src/slic3r/GUI/MainFrame.cpp:473 msgid "Send to print current plate as G-code" -msgstr "Enviar para imprimir prato atual como G-code" +msgstr "Enviar para imprimir a bandeja atual como G-code" #: src/slic3r/GUI/MainFrame.cpp:478 msgid "Export plate as &STL" -msgstr "Exportar prato como &STL" +msgstr "Exportar bandeja como &STL" #: src/slic3r/GUI/MainFrame.cpp:478 msgid "Export current plate as STL" -msgstr "Exporte o prato atual como STL" +msgstr "Exporte a bandeja atual como STL" #: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export plate as STL &including supports" -msgstr "Exportar prato como STL &incluindo suportes" +msgstr "Exportar bandeja como STL incluindo suportes" #: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export current plate as STL including supports" -msgstr "Exporte o prato atual como o STL que inclui suportes" +msgstr "Exporte a bandeja atual como o STL que inclui suportes" #: src/slic3r/GUI/MainFrame.cpp:484 msgid "Export plate as &AMF" -msgstr "Exportar prato como &AMF" +msgstr "Exportar bandeja como &AMF" #: src/slic3r/GUI/MainFrame.cpp:484 msgid "Export current plate as AMF" -msgstr "Exporte o prato atual como o AMF" +msgstr "Exporte a bandeja atual como o AMF" #: src/slic3r/GUI/MainFrame.cpp:488 msgid "Export &toolpaths as OBJ" @@ -2804,11 +2804,11 @@ msgstr "Colar área de transferência" #: src/slic3r/GUI/MainFrame.cpp:590 msgid "&Plater Tab" -msgstr "&Prato" +msgstr "&Bandeja" #: src/slic3r/GUI/MainFrame.cpp:590 msgid "Show the plater" -msgstr "Mostrar o prato" +msgstr "Mostrar a bandeja" #: src/slic3r/GUI/MainFrame.cpp:597 msgid "P&rint Settings Tab" @@ -6198,7 +6198,7 @@ msgstr "Distância entre cópias" #: src/libslic3r/PrintConfig.cpp:352 msgid "Distance used for the auto-arrange feature of the plater." -msgstr "Distância usada para o recurso de organizar automaticamente o prato." +msgstr "Distância usada para o recurso de organizar automaticamente a bandeja." #: src/libslic3r/PrintConfig.cpp:359 msgid "Elephant foot compensation" @@ -6395,8 +6395,8 @@ msgid "" msgstr "" "Defina isso para o raio de folga em torno de sua extrusora. Se a extrusora " "não estiver centralizada, escolha o maior valor para a segurança. Essa " -"config. é usada para verificar colisões e exibir a visualização gráfica no " -"prato." +"config. é usada para verificar colisões e exibir a visualização gráfica na " +"bandeja." #: src/libslic3r/PrintConfig.cpp:505 msgid "Extruder Color" From 053818d0285aeec186cdc9aa874133c877a3924d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 21 Jan 2020 09:44:18 +0100 Subject: [PATCH 81/85] Fix MPFR being built as shared library --- deps/MPFR/MPFR.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/MPFR/MPFR.cmake b/deps/MPFR/MPFR.cmake index 17ac283ea..cda7eeea9 100644 --- a/deps/MPFR/MPFR.cmake +++ b/deps/MPFR/MPFR.cmake @@ -21,7 +21,7 @@ else () ExternalProject_Add(dep_MPFR URL http://ftp.vim.org/ftp/gnu/mpfr/mpfr-3.1.6.tar.bz2 https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2 # mirrors are allowed BUILD_IN_SOURCE ON - CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --with-gmp=${DESTDIR}/usr/local --with-pic + CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --enable-shared=no --enable-static=yes --with-gmp=${DESTDIR}/usr/local --with-pic BUILD_COMMAND make -j INSTALL_COMMAND make install DEPENDS dep_GMP From c627114830a5d9411033aa8535b2d505ae7536ee Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 21 Jan 2020 10:14:25 +0100 Subject: [PATCH 82/85] Fixed missing "&" in Brazilian Portugal translation. --- resources/localization/pt_br/PrusaSlicer_pt_br.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/localization/pt_br/PrusaSlicer_pt_br.po b/resources/localization/pt_br/PrusaSlicer_pt_br.po index 647a9dd4f..30c0687a5 100644 --- a/resources/localization/pt_br/PrusaSlicer_pt_br.po +++ b/resources/localization/pt_br/PrusaSlicer_pt_br.po @@ -2655,7 +2655,7 @@ msgstr "Exporte a bandeja atual como STL" #: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export plate as STL &including supports" -msgstr "Exportar bandeja como STL incluindo suportes" +msgstr "Exportar bandeja como STL &incluindo suportes" #: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export current plate as STL including supports" From 858e936e52db89f75c5946acb392e9b112b89c00 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 20 Jan 2020 11:20:18 +0100 Subject: [PATCH 83/85] Fix incorrect filename case in test_3mf --- tests/libslic3r/test_3mf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 5f1c74c36..6b60182b5 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -26,7 +26,7 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { GIVEN("world vertices coordinates before save") { // load a model from stl file Model src_model; - std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.stl"; + std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl"; load_stl(src_file.c_str(), &src_model); src_model.add_default_instances(); From 6eaf48ebd8cc9f6436ccd9a4e1b24899c87e7e5e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 20 Jan 2020 15:08:19 +0100 Subject: [PATCH 84/85] Implemented check of color change event respecting to mode + unresolved ticks are marked with error_tick icon + some code refactoring --- resources/icons/error_tick.svg | 12 + src/slic3r/GUI/wxExtensions.cpp | 583 +++++++++++++++++++------------- src/slic3r/GUI/wxExtensions.hpp | 48 ++- 3 files changed, 391 insertions(+), 252 deletions(-) create mode 100644 resources/icons/error_tick.svg diff --git a/resources/icons/error_tick.svg b/resources/icons/error_tick.svg new file mode 100644 index 000000000..6467d29fb --- /dev/null +++ b/resources/icons/error_tick.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 7689e31cb..8f43f6c30 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2325,7 +2325,7 @@ DoubleSlider::DoubleSlider( wxWindow *parent, m_cog_icon_dim = int((float)m_bmp_cog.bmp().GetSize().x / scale_factor); m_selection = ssUndef; - m_pause_print_msg = _utf8(L("Place bearings in slots and resume")); + m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume"))); // slider events Bind(wxEVT_PAINT, &DoubleSlider::OnPaint, this); @@ -2539,13 +2539,13 @@ Slic3r::Model::CustomGCodeInfo DoubleSlider::GetTicksValues() const const int val_size = m_values.size(); if (!m_values.empty()) - for (const TICK_CODE& tick : m_ticks) { + for (const TICK_CODE& tick : m_ticks.ticks) { if (tick.tick > val_size) break; values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color}); } - custom_gcode_per_print_z.mode = m_mode; + custom_gcode_per_print_z.mode = m_force_mode_apply ? m_mode : m_ticks.mode; return custom_gcode_per_print_z; } @@ -2554,13 +2554,13 @@ void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_g { if (m_values.empty()) { - m_ticks_mode = m_mode; + m_ticks.mode = m_mode; return; } const bool was_empty = m_ticks.empty(); - m_ticks.clear(); + m_ticks.ticks.clear(); const std::vector& heights = custom_gcode_per_print_z.gcodes; for (auto h : heights) { auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon()); @@ -2568,14 +2568,14 @@ void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_g if (it == m_values.end()) continue; - m_ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); + m_ticks.ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); } if (!was_empty && m_ticks.empty()) // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one post_ticks_changed_event(); - m_ticks_mode = custom_gcode_per_print_z.mode; + m_ticks.mode = custom_gcode_per_print_z.mode; Refresh(); Update(); @@ -2649,7 +2649,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin return; wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); - if (m_ticks.find(TICK_CODE{tick}) != m_ticks.end()) + if (m_ticks.ticks.find(TICK_CODE{tick}) != m_ticks.ticks.end()) icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); wxCoord x_draw, y_draw; @@ -2792,7 +2792,7 @@ void DoubleSlider::draw_ticks(wxDC& dc) int height, width; get_size(&width, &height); const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width; - for (auto tick : m_ticks) + for (auto tick : m_ticks.ticks) { const wxCoord pos = get_position_from_value(tick.tick); @@ -2801,11 +2801,23 @@ void DoubleSlider::draw_ticks(wxDC& dc) is_horizontal() ? dc.DrawLine(pos, mid+14, pos, mid+9) : dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/); + wxBitmap icon = wxNullBitmap; + // Draw icon for "Pause print" or "Custom Gcode" if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ToolChangeCode) + icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode"); + else { - wxBitmap icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode"); + if ((tick.gcode == Slic3r::ColorChangeCode && ( + (m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) || + (m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) )) || + (tick.gcode == Slic3r::ToolChangeCode && + (m_ticks.mode == t_mode::MultiAsSingle && m_mode != t_mode::MultiAsSingle ) )) + icon = create_scaled_bitmap(this, "error_tick"); + } + if (!icon.IsNull()) + { wxCoord x_draw, y_draw; is_horizontal() ? x_draw = pos - 0.5 * m_tick_icon_dim : y_draw = pos - 0.5 * m_tick_icon_dim; is_horizontal() ? y_draw = mid + 22 : x_draw = mid + m_thumb_size.x + 3; @@ -2820,7 +2832,7 @@ std::string DoubleSlider::get_color_for_tool_change_tick(std::set::co const int current_extruder = it->extruder == 0 ? std::max(m_only_extruder, 1) : it->extruder; auto it_n = it; - while (it_n != m_ticks.begin()) { + while (it_n != m_ticks.ticks.begin()) { --it_n; if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder) return it_n->color; @@ -2834,7 +2846,7 @@ std::string DoubleSlider::get_color_for_color_change_tick(std::set::c const int def_extruder = std::max(1, m_only_extruder); auto it_n = it; bool is_tool_change = false; - while (it_n != m_ticks.begin()) { + while (it_n != m_ticks.ticks.begin()) { --it_n; if (it_n->gcode == Slic3r::ToolChangeCode) { is_tool_change = true; @@ -2881,9 +2893,9 @@ void DoubleSlider::draw_colored_band(wxDC& dc) const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0; draw_band(dc, wxColour(Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band); - std::set::const_iterator tick_it = m_ticks.begin(); + std::set::const_iterator tick_it = m_ticks.ticks.begin(); - while (tick_it != m_ticks.end()) + while (tick_it != m_ticks.ticks.end()) { if ( (m_mode == t_mode::SingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) || (m_mode == t_mode::MultiAsSingle && (tick_it->gcode == Slic3r::ToolChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) ) @@ -2993,7 +3005,7 @@ bool DoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect) int DoubleSlider::is_point_near_tick(const wxPoint& pt) { - for (auto tick : m_ticks) { + for (auto tick : m_ticks.ticks) { const wxCoord pos = get_position_from_value(tick.tick); if (is_horizontal()) { @@ -3030,8 +3042,13 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) wxClientDC dc(this); wxPoint pos = event.GetLogicalPosition(dc); - if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) { - action_tick(taOnIcon); + if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) + { + const auto it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); + if (it == m_ticks.ticks.end()) + m_force_add_tick = true; + else + m_force_delete_tick = true; return; } @@ -3054,12 +3071,13 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) m_selection == ssLower ? correct_lower_value() : correct_higher_value(); if (!m_selection) m_selection = ssHigher; - m_ticks.clear(); + m_ticks.ticks.clear(); post_ticks_changed_event(); } else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == t_mode::MultiExtruder) { // show dialog for set extruder sequence - m_edit_extruder_sequence = true; + m_force_edit_extruder_sequence = true; + return; } else detect_selected_slider(pos); @@ -3127,8 +3145,8 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus) else if (m_is_action_icon_focesed) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - const auto tick_code_it = m_ticks.find(TICK_CODE{tick}); - tooltip = tick_code_it == m_ticks.end() ? (m_mode == t_mode::MultiAsSingle ? + const auto tick_code_it = m_ticks.ticks.find(TICK_CODE{tick}); + tooltip = tick_code_it == m_ticks.ticks.end() ? (m_mode == t_mode::MultiAsSingle ? _(L("For add change extruder use left mouse button click")) : _(L("For add color change use left mouse button click")) ) + "\n" + _(L("For add another code use right mouse button click")) : @@ -3211,10 +3229,8 @@ void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu) if (m_mode == t_mode::MultiAsSingle) append_menu_item(change_extruder_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { change_extruder(i); }, "", menu, + [this, i](wxCommandEvent&) { add_code_as_tick(Slic3r::ToolChangeCode, i); }, "", menu, [is_active_extruder]() { return !is_active_extruder; }, Slic3r::GUI::wxGetApp().plater()); -// append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "", -// [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder); } const wxString change_extruder_menu_name = m_mode == t_mode::MultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)")); @@ -3245,13 +3261,13 @@ void DoubleSlider::append_add_color_change_menu_item(wxMenu* menu) (is_used_extruder ? " (" + _(L("used")) + ")" : ""); append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", - [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", menu, + [this, i](wxCommandEvent&) { add_code_as_tick(Slic3r::ColorChangeCode, i); }, "", menu, [is_used_extruder]() { return is_used_extruder; }, Slic3r::GUI::wxGetApp().plater()); } const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str()); wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); - add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m")); + add_color_change_menu_item->SetBitmap(create_scaled_bitmap(this, "colorchange_add_m")); } } @@ -3262,28 +3278,21 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event) this->ReleaseMouse(); m_is_left_down = false; - if (m_show_context_menu) + if (m_force_delete_tick) { - if (m_mode == t_mode::SingleExtruder) - add_code(Slic3r::ColorChangeCode); - else - { - wxMenu menu; - - if (m_mode == t_mode::MultiAsSingle) - append_change_extruder_menu_item(&menu); - else - append_add_color_change_menu_item(&menu); - - Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); - } - - m_show_context_menu = false; + delete_current_tick(); + m_force_delete_tick = false; } - - if (m_edit_extruder_sequence) { + else + if (m_force_add_tick) + { + add_current_tick(); + m_force_add_tick = false; + } + else + if (m_force_edit_extruder_sequence) { edit_extruder_sequence(); - m_edit_extruder_sequence = false; + m_force_edit_extruder_sequence = false; } Refresh(); @@ -3329,45 +3338,6 @@ void DoubleSlider::move_current_thumb(const bool condition) ProcessWindowEvent(e); } -void DoubleSlider::action_tick(const TicksAction action) -{ - if (m_selection == ssUndef) - return; - - const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - - const auto it = m_ticks.find(TICK_CODE{tick}); - - if (it != m_ticks.end()) // erase this tick - { - if (action == taAdd) - return; - m_ticks.erase(TICK_CODE{tick}); - - post_ticks_changed_event(it->gcode); - Refresh(); - Update(); - return; - } - - if (action == taDel) - return; - if (action == taAdd) - { - // OnChar() is called immediately after OnKeyDown(), which can cause call of add_code() twice. - // To avoid this case we should suppress second add_code() call. - if (m_suppress_add_code) - return; - m_suppress_add_code = true; - if (m_mode == t_mode::SingleExtruder) // if (m_mode != t_mode::MultiExtruder) - add_code(Slic3r::ColorChangeCode); - m_suppress_add_code = false; - return; - } - - m_show_context_menu = true; -} - void DoubleSlider::OnWheel(wxMouseEvent& event) { // Set nearest to the mouse thumb as a selected, if there is not selected thumb @@ -3391,10 +3361,18 @@ void DoubleSlider::OnWheel(wxMouseEvent& event) void DoubleSlider::OnKeyDown(wxKeyEvent &event) { const int key = event.GetKeyCode(); - if (key == WXK_NUMPAD_ADD) - action_tick(taAdd); - else if (key == 390 || key == WXK_DELETE || key == WXK_BACK) - action_tick(taDel); + if (key == WXK_NUMPAD_ADD) { + // OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice. + // To avoid this case we should suppress second add_tick() call. + m_ticks.suppress_plus(true); + add_current_tick(true); + } + else if (key == 390 || key == WXK_DELETE || key == WXK_BACK) { + // OnChar() is called immediately after OnKeyDown(), which can cause call of delete_tick() twice. + // To avoid this case we should suppress second delete_tick() call. + m_ticks.suppress_minus(true); + delete_current_tick(); + } else if (is_horizontal()) { if (key == WXK_LEFT || key == WXK_RIGHT) @@ -3428,10 +3406,14 @@ void DoubleSlider::OnKeyUp(wxKeyEvent &event) void DoubleSlider::OnChar(wxKeyEvent& event) { const int key = event.GetKeyCode(); - if (key == '+') - action_tick(taAdd); - else if (key == '-') - action_tick(taDel); + if (key == '+' && !m_ticks.suppressed_plus()) { + add_current_tick(true); + m_ticks.suppress_plus(false); + } + else if (key == '-' && !m_ticks.suppressed_minus()) { + delete_current_tick(); + m_ticks.suppress_minus(false); + } } void DoubleSlider::OnRightDown(wxMouseEvent& event) @@ -3446,8 +3428,8 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick - auto it = m_ticks.find(TICK_CODE{ tick }); - if (it == m_ticks.end()) + auto it = m_ticks.ticks.find(TICK_CODE{ tick }); + if (it == m_ticks.ticks.end()) { // show context menu on OnRightUp() m_show_context_menu = true; @@ -3484,8 +3466,8 @@ int DoubleSlider::get_extruder_for_tick(int tick) if (m_ticks.empty()) return default_initial_extruder; - auto it = m_ticks.lower_bound(TICK_CODE{tick}); - while (it != m_ticks.begin()) { + auto it = m_ticks.ticks.lower_bound(TICK_CODE{tick}); + while (it != m_ticks.ticks.begin()) { --it; if(it->gcode == Slic3r::ToolChangeCode) return it->extruder; @@ -3522,16 +3504,17 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) return {default_initial_extruder}; std::set used_extruders; - auto it_start = m_ticks.lower_bound(TICK_CODE{tick}); + const std::set& ticks = m_ticks.ticks; + auto it_start = ticks.lower_bound(TICK_CODE{tick}); auto it = it_start; - if (it == m_ticks.begin() && it->gcode == Slic3r::ToolChangeCode) { + if (it == ticks.begin() && it->gcode == Slic3r::ToolChangeCode) { used_extruders.emplace(it->extruder); if (tick < it->tick) used_extruders.emplace(default_initial_extruder); } - while (it != m_ticks.begin()) { + while (it != ticks.begin()) { --it; if(it->gcode == Slic3r::ToolChangeCode) { @@ -3540,11 +3523,11 @@ std::set DoubleSlider::get_used_extruders_for_tick(int tick) } } - if (it == m_ticks.begin() && used_extruders.empty()) + if (it == ticks.begin() && used_extruders.empty()) used_extruders.emplace(default_initial_extruder); it = it_start; - while (it != m_ticks.end()) { + while (it != ticks.end()) { if(it->gcode == Slic3r::ToolChangeCode) used_extruders.emplace(it->extruder); ++it; @@ -3565,7 +3548,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) if (m_mode == t_mode::SingleExtruder) append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", - [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu, + [this](wxCommandEvent&) { add_code_as_tick(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu, [](){return true;}, this); else { @@ -3574,11 +3557,11 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) } append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "", - [this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu, + [this](wxCommandEvent&) { add_code_as_tick(Slic3r::PausePrintCode); }, "pause_print", &menu, []() {return true; }, this); append_menu_item(&menu, wxID_ANY, _(L("Add custom G-code")), "", - [this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu, + [this](wxCommandEvent&) { add_code_as_tick(""); }, "edit_gcode", &menu, []() {return true; }, this); Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); @@ -3588,7 +3571,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) else if (m_show_edit_menu) { wxMenu menu; - std::set::iterator it = m_ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); + std::set::iterator it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); const bool is_color_change = it->gcode == Slic3r::ColorChangeCode; append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) : @@ -3599,7 +3582,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Delete color change")) : it->gcode == Slic3r::PausePrintCode ? _(L("Delete pause print")) : _(L("Delete custom G-code")), "", - [this](wxCommandEvent&) { action_tick(taDel); }, "colorchange_del_f", &menu); + [this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu); Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu); @@ -3656,123 +3639,100 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height) return into_u8(dlg.GetValue()); } -void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) +void DoubleSlider::add_code_as_tick(std::string code, int selected_extruder/* = -1*/) { + if (m_selection == ssUndef) + return; const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - // if on this Z doesn't exist tick - auto it = m_ticks.find(TICK_CODE{ tick }); - if (it != m_ticks.end()) + + if (m_ticks.ticks.find(TICK_CODE{ tick }) != m_ticks.ticks.end() || // if on this Z doesn't exist tick + !check_ticks_changed_event(code)) return; - std::string color; const int extruder = selected_extruder > 0 ? selected_extruder : std::max(1, m_only_extruder); - if (code == Slic3r::ColorChangeCode) - { - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - - if (m_ticks.empty()) - color = colors[extruder-1]; - else - { - auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick }); - while (before_tick_it != m_ticks.begin()) { - --before_tick_it; - if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) { - color = before_tick_it->color; - break; - } - } - - if (color.empty()) - color = colors[extruder-1]; - } - - color = get_new_color(color); - if (color.empty()) - return; - } - else if (code == Slic3r::PausePrintCode) - { - /* PausePrintCode doesn't need a color, so - * this field is used for save a short message shown on Printer display - * */ - color = get_pause_print_msg(m_pause_print_msg, m_values[tick]); - if (color.empty()) - return; - m_pause_print_msg = color; - } - else if (code.empty()) - { - code = get_custom_code(m_custom_gcode, m_values[tick]); - if (code.empty()) - return; - m_custom_gcode = code; - } - - m_ticks.emplace(TICK_CODE{tick, code, extruder, color}); + if (!m_ticks.add_tick(tick, code, extruder, m_values[tick])) + return; post_ticks_changed_event(code); - Refresh(); - Update(); +} + +void DoubleSlider::add_current_tick(bool call_from_keyboard /*= false*/) +{ + if (m_selection == ssUndef) + return; + const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; + auto it = m_ticks.ticks.find(TICK_CODE{ tick }); + + if (it != m_ticks.ticks.end() || // this tick is already exist + !check_ticks_changed_event(m_mode == t_mode::MultiAsSingle ? Slic3r::ToolChangeCode : Slic3r::ColorChangeCode)) + return; + + if (m_mode == t_mode::SingleExtruder) + add_code_as_tick(Slic3r::ColorChangeCode); + else + { + wxMenu menu; + + if (m_mode == t_mode::MultiAsSingle) + append_change_extruder_menu_item(&menu); + else + append_add_color_change_menu_item(&menu); + + wxPoint pos = wxDefaultPosition; + if (call_from_keyboard) + { + int width, height; + get_size(&width, &height); + + const wxCoord coord = 0.75 * (is_horizontal() ? height : width); + this->GetPosition(&width, &height); + + pos = is_horizontal() ? + wxPoint(get_position_from_value(tick), height + coord) : + wxPoint(width + coord, get_position_from_value(tick)); + } + + Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu, pos); + } +} + +void DoubleSlider::delete_current_tick() +{ + if (m_selection == ssUndef) + return; + auto it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); + + if (it != m_ticks.ticks.end()) + { + if (!check_ticks_changed_event(it->gcode)) + return; + + const std::string code = it->gcode; + m_ticks.ticks.erase(it); + post_ticks_changed_event(code); + } } void DoubleSlider::edit_tick() { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - // if on this Z exists tick - std::set::iterator it = m_ticks.find(TICK_CODE{ tick }); - if (it != m_ticks.end()) - { - std::string edited_value; - if (it->gcode == Slic3r::ColorChangeCode) - edited_value = get_new_color(it->color); - else if (it->gcode == Slic3r::PausePrintCode) - edited_value = get_pause_print_msg(it->color, m_values[it->tick]); - else - edited_value = get_custom_code(it->gcode, m_values[it->tick]); + const std::set::iterator it = m_ticks.ticks.find(TICK_CODE{ tick }); - if (edited_value.empty()) - return; + if (it == m_ticks.ticks.end() || // if on this Z exists tick + !check_ticks_changed_event(it->gcode)) + return; - TICK_CODE changed_tick = *it; - if (it->gcode == Slic3r::ColorChangeCode || it->gcode == Slic3r::PausePrintCode) { - if (it->color == edited_value) - return; - changed_tick.color = edited_value; - } - else { - if (it->gcode == edited_value) - return; - changed_tick.gcode = edited_value; - } - - m_ticks.erase(it); - m_ticks.emplace(changed_tick); - - post_ticks_changed_event(changed_tick.gcode); - } -} - -void DoubleSlider::change_extruder(int extruder) -{ - const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - - // if on this Y doesn't exist tick - if (m_ticks.find(TICK_CODE{tick}) == m_ticks.end()) - { - m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); - - post_ticks_changed_event(Slic3r::ToolChangeCode); - Refresh(); - Update(); - } + const std::string code = it->gcode; + if (m_ticks.edit_tick(it, m_values[it->tick])) + post_ticks_changed_event(code); } void DoubleSlider::edit_extruder_sequence() { + if (!check_ticks_changed_event(Slic3r::ToolChangeCode)) + return; + Slic3r::GUI::ExtruderSequenceDialog dlg(m_extruders_sequence); if (dlg.ShowModal() != wxID_OK) return; @@ -3783,13 +3743,7 @@ void DoubleSlider::edit_extruder_sequence() m_extruders_sequence = from_dlg_val; - auto it = m_ticks.begin(); - while (it != m_ticks.end()) { - if (it->gcode == Slic3r::ToolChangeCode) - it = m_ticks.erase(it); - else - ++it; - } + m_ticks.erase_all_ticks_with_code(Slic3r::ToolChangeCode); int tick = 0; double value = 0.0; @@ -3800,8 +3754,8 @@ void DoubleSlider::edit_extruder_sequence() while (tick <= m_max_value) { - int cur_extruder = m_extruders_sequence.extruders[extruder]; - m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]}); + const int cur_extruder = m_extruders_sequence.extruders[extruder]; + m_ticks.ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]}); extruder++; if (extruder == extr_cnt) @@ -3825,40 +3779,183 @@ void DoubleSlider::edit_extruder_sequence() void DoubleSlider::post_ticks_changed_event(const std::string& gcode /*= ""*/) { - if ( m_ticks_mode == m_mode || - (gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) ) - { - wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); - return; - } - - if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle) - { - } - - if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder) - { - } - - if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::SingleExtruder) - { - } - - if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::MultiExtruder) - { - } - - if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) - { - } - - if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle) - { - } + m_force_mode_apply = (gcode.empty() || gcode == Slic3r::ColorChangeCode || gcode == Slic3r::ToolChangeCode); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } +bool DoubleSlider::check_ticks_changed_event(const std::string& gcode) +{ + if ( m_ticks.mode == m_mode || + (gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) || + (m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle) || // All ColorChanges will be applied for 1st extruder + (m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle) ) // Just mark ColorChanges for all unused extruders + return true; + + if ((m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) || + (m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) ) + { + if (!m_ticks.has_tick_with_code(Slic3r::ColorChangeCode)) + return true; + + wxString message = (m_ticks.mode == t_mode::SingleExtruder ? + _(L("The last color change data was saved for a single extruder printer profile.")) : + _(L("The last color change data was saved for a multiple extruder printer profile.")) + ) + "\n" + + _(L("Your current changes will cause a deletion of all saved color changes.")) + "\n\n\t" + + _(L("Are you sure you want to continue?")); + + wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO); + if (msg.ShowModal() == wxID_YES) { + m_ticks.erase_all_ticks_with_code(Slic3r::ColorChangeCode); + post_ticks_changed_event(Slic3r::ColorChangeCode); + } + return false; + } + // m_ticks_mode == t_mode::MultiAsSingle + if( m_ticks.has_tick_with_code(Slic3r::ToolChangeCode) ) + { + wxString message = m_mode == t_mode::SingleExtruder ? ( + _(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" + + _(L("Select YES if you want to delete all saved tool changes, \n\t" + "NO if you want all tool changes switch to color changes, \n\t" + "or CANCEL for do nothing")) + "\n\n\t" + + _(L("Do you want to delete all saved tool changes?")) + ) : ( // t_mode::MultiExtruder + _(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" + + _(L("Your current changes will cause a deletion of all saved tool changes.")) + "\n\n\t" + + _(L("Are you sure you want to continue?")) ) ; + + wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO | (m_mode == t_mode::SingleExtruder ? wxCANCEL : 0)); + const int answer = msg.ShowModal(); + if (answer == wxID_YES) { + m_ticks.erase_all_ticks_with_code(Slic3r::ToolChangeCode); + post_ticks_changed_event(Slic3r::ToolChangeCode); + } + else if (m_mode == t_mode::SingleExtruder && answer == wxID_NO) { + m_ticks.switch_code(Slic3r::ToolChangeCode, Slic3r::ColorChangeCode); + post_ticks_changed_event(Slic3r::ColorChangeCode); + } + return false; + } + + return true; +} + +bool DoubleSlider::TICK_CODE_INFO::add_tick(const int tick, std::string& code, const int extruder, double print_z) +{ + std::string color; + if (code.empty()) // custom Gcode + { + code = get_custom_code(custom_gcode, print_z); + if (code.empty()) + return false; + custom_gcode = code; + } + else if (code == Slic3r::PausePrintCode) + { + /* PausePrintCode doesn't need a color, so + * this field is used for save a short message shown on Printer display + * */ + color = get_pause_print_msg(pause_print_msg, print_z); + if (color.empty()) + return false; + pause_print_msg = color; + } + else + { + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + color = colors[extruder - 1]; + + if (code == Slic3r::ColorChangeCode) + { + if (!ticks.empty()) + { + auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), TICK_CODE{ tick }); + while (before_tick_it != ticks.begin()) { + --before_tick_it; + if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) { + color = before_tick_it->color; + break; + } + } + } + + color = get_new_color(color); + if (color.empty()) + return false; + } + } + + ticks.emplace(TICK_CODE{ tick, code, extruder, color }); + return true; +} + +bool DoubleSlider::TICK_CODE_INFO::edit_tick(std::set::iterator it, double print_z) +{ + std::string edited_value; + if (it->gcode == Slic3r::ColorChangeCode) + edited_value = get_new_color(it->color); + else if (it->gcode == Slic3r::PausePrintCode) + edited_value = get_pause_print_msg(it->color, print_z); + else + edited_value = get_custom_code(it->gcode, print_z); + + if (edited_value.empty()) + return false; + + TICK_CODE changed_tick = *it; + if (it->gcode == Slic3r::ColorChangeCode || it->gcode == Slic3r::PausePrintCode) { + if (it->color == edited_value) + return false; + changed_tick.color = edited_value; + } + else { + if (it->gcode == edited_value) + return false; + changed_tick.gcode = edited_value; + } + + ticks.erase(it); + ticks.emplace(changed_tick); + + return true; +} + +void DoubleSlider::TICK_CODE_INFO::switch_code(const std::string& code_from, const std::string& code_to) +{ + for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) + if (it->gcode == code_from) + { + TICK_CODE tick = *it; + tick.gcode = code_to; + tick.extruder = 1; + ticks.erase(it); + it = ticks.emplace(tick).first; + } + else + ++it; +} + +void DoubleSlider::TICK_CODE_INFO::erase_all_ticks_with_code(const std::string& gcode) +{ + for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) { + if (it->gcode == gcode) + it = ticks.erase(it); + else + ++it; + } +} + +bool DoubleSlider::TICK_CODE_INFO::has_tick_with_code(const std::string& gcode) +{ + for (const TICK_CODE& tick : ticks) + if (tick.gcode == gcode) + return true; + + return false; +} + // ---------------------------------------------------------------------------- // LockButton diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 5b9f6db0b..8cae495ef 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -844,9 +844,13 @@ public: void OnChar(wxKeyEvent &event); void OnRightDown(wxMouseEvent& event); void OnRightUp(wxMouseEvent& event); - void add_code(std::string code, int selected_extruder = -1); + + void add_code_as_tick(std::string code, int selected_extruder = -1); + // add default action for tick, when press "+" + void add_current_tick(bool call_from_keyboard = false); + // delete current tick, when press "-" + void delete_current_tick(); void edit_tick(); - void change_extruder(int extruder); void edit_extruder_sequence(); struct TICK_CODE @@ -882,7 +886,6 @@ protected: void correct_lower_value(); void correct_higher_value(); void move_current_thumb(const bool condition); - void action_tick(const TicksAction action); void enter_window(wxMouseEvent& event, const bool enter); private: @@ -906,6 +909,7 @@ private: std::set get_used_extruders_for_tick(int tick); void post_ticks_changed_event(const std::string& gcode = ""); + bool check_ticks_changed_event(const std::string& gcode); void append_change_extruder_menu_item(wxMenu*); void append_add_color_change_menu_item(wxMenu*); @@ -937,11 +941,11 @@ private: bool m_is_enabled_tick_manipulation = true; bool m_show_context_menu = false; bool m_show_edit_menu = false; - bool m_edit_extruder_sequence = false; - bool m_suppress_add_code = false; + bool m_force_edit_extruder_sequence = false; + bool m_force_mode_apply = true; + bool m_force_add_tick = false; + bool m_force_delete_tick = false; t_mode m_mode = t_mode::SingleExtruder; - std::string m_custom_gcode = ""; - std::string m_pause_print_msg; int m_only_extruder = -1; wxRect m_rect_lower_thumb; @@ -972,8 +976,34 @@ private: std::vector m_line_pens; std::vector m_segm_pens; std::vector m_values; - std::set m_ticks; - t_mode m_ticks_mode; + + struct TICK_CODE_INFO + { + std::set ticks; + t_mode mode = t_mode::SingleExtruder; + + bool empty() const { return ticks.empty(); } + void set_pause_print_msg(const std::string& message) { pause_print_msg = message; } + + bool add_tick (const int tick, std::string &code, int extruder, double print_z); + bool edit_tick (std::set::iterator it, double print_z); + void switch_code(const std::string& code_from, const std::string& code_to); + void erase_all_ticks_with_code (const std::string& gcode); + bool has_tick_with_code (const std::string& gcode); + + void suppress_plus (bool suppress) { m_suppress_plus = suppress;} + void suppress_minus(bool suppress) { m_suppress_minus = suppress;} + bool suppressed_plus () { return m_suppress_plus ; } + bool suppressed_minus() { return m_suppress_minus; } + + private: + + std::string custom_gcode = ""; + std::string pause_print_msg = ""; + bool m_suppress_plus = false; + bool m_suppress_minus = false; + } + m_ticks; public: struct ExtrudersSequence From 05ea01bdcccb3d8bc5d46b71c20a30e25352cea8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 21 Jan 2020 12:10:02 +0100 Subject: [PATCH 85/85] Ported PlaceholderParser unit tests to C++. --- src/libslic3r/PlaceholderParser.cpp | 3 +- src/libslic3r/PlaceholderParser.hpp | 2 +- t/custom_gcode.t | 69 +------------------ tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_placeholder_parser.cpp | 74 +++++++++++++++++++++ 5 files changed, 79 insertions(+), 70 deletions(-) create mode 100644 tests/libslic3r/test_placeholder_parser.cpp diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index c92be2845..bbf32a141 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1152,7 +1152,8 @@ namespace client [ px::bind(&expr::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') [ px::bind(&expr::max, _val, _2) ] - | (kw["int"] > '(' > unary_expression(_r1) ) [ px::bind(&FactorActions::to_int, _1, _val) ] + //FIXME this is likley not correct + | (kw["int"] > '(' > unary_expression(_r1) /* > ')' */ ) [ px::bind(&FactorActions::to_int, _1, _val) ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp index 14fdc5c28..d744dba22 100644 --- a/src/libslic3r/PlaceholderParser.hpp +++ b/src/libslic3r/PlaceholderParser.hpp @@ -41,7 +41,7 @@ public: // Fill in the template using a macro processing language. // Throws std::runtime_error on syntax or runtime error. - std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr) const; + std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const; // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. // Throws std::runtime_error on syntax or runtime error. diff --git a/t/custom_gcode.t b/t/custom_gcode.t index 5ffd9b7f4..44f952318 100644 --- a/t/custom_gcode.t +++ b/t/custom_gcode.t @@ -1,4 +1,4 @@ -use Test::More tests => 81; +use Test::More tests => 41; use strict; use warnings; @@ -45,73 +45,6 @@ use Slic3r::Test; #========================================================== -{ - my $parser = Slic3r::GCode::PlaceholderParser->new; - my $config = Slic3r::Config::new_from_defaults; - $config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 '); - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $parser->apply_config($config); - $parser->set('foo' => 0); - $parser->set('bar' => 2); - $parser->set('num_extruders' => 4); - is $parser->process('[temperature_[foo]]'), - $config->temperature->[0], - "nested config options (legacy syntax)"; - is $parser->process('{temperature[foo]}'), - $config->temperature->[0], - "array reference"; - is $parser->process("test [ temperature_ [foo] ] \n hu"), - "test " . $config->temperature->[0] . " \n hu", - "whitespaces and newlines are maintained"; - is $parser->process('{2*3}'), '6', 'math: 2*3'; - is $parser->process('{2*3/6}'), '1', 'math: 2*3/6'; - is $parser->process('{2*3/12}'), '0', 'math: 2*3/12'; - ok abs($parser->process('{2.*3/12}') - 0.5) < 1e-7, 'math: 2.*3/12'; - is $parser->process('{10%2.5}') '0', 'math: 10 % 2.5'; - is $parser->process('{11/2.5-1}') '1', 'math: 11 % 2.5'; - is $parser->process('{2*(3-12)}'), '-18', 'math: 2*(3-12)'; - is $parser->process('{2*foo*(3-12)}'), '0', 'math: 2*foo*(3-12)'; - is $parser->process('{2*bar*(3-12)}'), '-36', 'math: 2*bar*(3-12)'; - ok abs($parser->process('{2.5*bar*(3-12)}') - -45) < 1e-7, 'math: 2.5*bar*(3-12)'; - is $parser->process('{min(12, 14)}'), '12', 'math: min(12, 14)'; - is $parser->process('{max(12, 14)}'), '14', 'math: max(12, 14)'; - is $parser->process('{min(13.4, -1238.1)}'), '-1238.1', 'math: min(13.4, -1238.1)'; - is $parser->process('{max(13.4, -1238.1)}'), '13.4', 'math: max(13.4, -1238.1)'; - is $parser->process('{int(13.4)}'), '13', 'math: int(13.4)'; - - # Test the boolean expression parser. - is $parser->evaluate_boolean_expression('12 == 12'), 1, 'boolean expression parser: 12 == 12'; - is $parser->evaluate_boolean_expression('12 != 12'), 0, 'boolean expression parser: 12 != 12'; - is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PATTERN.*/'), 1, 'boolean expression parser: regex matches'; - is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PTRN.*/'), 0, 'boolean expression parser: regex does not match'; - is $parser->evaluate_boolean_expression('foo + 2 == bar'), 1, 'boolean expression parser: accessing variables, equal'; - is $parser->evaluate_boolean_expression('foo + 3 == bar'), 0, 'boolean expression parser: accessing variables, not equal'; - - is $parser->evaluate_boolean_expression('(12 == 12) and (13 != 14)'), 1, 'boolean expression parser: (12 == 12) and (13 != 14)'; - is $parser->evaluate_boolean_expression('(12 == 12) && (13 != 14)'), 1, 'boolean expression parser: (12 == 12) && (13 != 14)'; - is $parser->evaluate_boolean_expression('(12 == 12) or (13 == 14)'), 1, 'boolean expression parser: (12 == 12) or (13 == 14)'; - is $parser->evaluate_boolean_expression('(12 == 12) || (13 == 14)'), 1, 'boolean expression parser: (12 == 12) || (13 == 14)'; - is $parser->evaluate_boolean_expression('(12 == 12) and not (13 == 14)'), 1, 'boolean expression parser: (12 == 12) and not (13 == 14)'; - is $parser->evaluate_boolean_expression('(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)'), 1, 'boolean expression parser: ternary true'; - is $parser->evaluate_boolean_expression('(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)'), 0, 'boolean expression parser: ternary false'; - is $parser->evaluate_boolean_expression('(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)'), 1, 'boolean expression parser: ternary false'; - is $parser->evaluate_boolean_expression('(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)'), 0, 'boolean expression parser: ternary true'; - is $parser->evaluate_boolean_expression('12 < 3'), 0, 'boolean expression parser: lower than - false'; - is $parser->evaluate_boolean_expression('12 < 22'), 1, 'boolean expression parser: lower than - true'; - is $parser->evaluate_boolean_expression('12 > 3'), 1, 'boolean expression parser: greater than - true'; - is $parser->evaluate_boolean_expression('12 > 22'), 0, 'boolean expression parser: greater than - false'; - is $parser->evaluate_boolean_expression('12 <= 3'), 0, 'boolean expression parser: lower than or equal- false'; - is $parser->evaluate_boolean_expression('12 <= 22'), 1, 'boolean expression parser: lower than or equal - true'; - is $parser->evaluate_boolean_expression('12 >= 3'), 1, 'boolean expression parser: greater than or equal - true'; - is $parser->evaluate_boolean_expression('12 >= 22'), 0, 'boolean expression parser: greater than or equal - false'; - is $parser->evaluate_boolean_expression('12 <= 12'), 1, 'boolean expression parser: lower than or equal (same values) - true'; - is $parser->evaluate_boolean_expression('12 >= 12'), 1, 'boolean expression parser: greater than or equal (same values) - true'; - - is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1'), 1, 'complex expression'; - is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)'), 1, 'complex expression2'; - is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)'), 0, 'complex expression3'; -} - { my $config = Slic3r::Config::new_from_defaults; $config->set('output_filename_format', 'ts_[travel_speed]_lh_[layer_height].gcode'); diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 02764589b..e34a40f34 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(${_TEST_NAME}_tests test_config.cpp test_elephant_foot_compensation.cpp test_geometry.cpp + test_placeholder_parser.cpp test_polygon.cpp test_stl.cpp ) diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp new file mode 100644 index 000000000..5802862b7 --- /dev/null +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -0,0 +1,74 @@ +#include + +#include "libslic3r/PlaceholderParser.hpp" +#include "libslic3r/PrintConfig.hpp" + +using namespace Slic3r; + +SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { + PlaceholderParser parser; + auto config = DynamicPrintConfig::full_print_config(); + + config.set_deserialize( { + { "printer_notes", " PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 " }, + { "nozzle_diameter", "0.6;0.6;0.6;0.6" }, + { "temperature", "357;359;363;378" } + }); + parser.apply_config(config); + parser.set("foo", 0); + parser.set("bar", 2); + parser.set("num_extruders", 4); + + SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); } + SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); } + SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); } + + // Test the math expressions. + SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); } + SECTION("math: 2*3/6") { REQUIRE(parser.process("{2*3/6}") == "1"); } + SECTION("math: 2*3/12") { REQUIRE(parser.process("{2*3/12}") == "0"); } + SECTION("math: 2.*3/12") { REQUIRE(std::stod(parser.process("{2.*3/12}")) == Approx(0.5)); } +// SECTION("math: 10 % 2.5") { REQUIRE(parser.process("{10%2.5}") == "0"); } +// SECTION("math: 11 / 2.5") { REQUIRE(parser.process("{11/2.5-1}") == "1"); } + SECTION("math: 2*(3-12)") { REQUIRE(parser.process("{2*(3-12)}") == "-18"); } + SECTION("math: 2*foo*(3-12)") { REQUIRE(parser.process("{2*foo*(3-12)}") == "0"); } + SECTION("math: 2*bar*(3-12)") { REQUIRE(parser.process("{2*bar*(3-12)}") == "-36"); } + SECTION("math: 2.5*bar*(3-12)") { REQUIRE(std::stod(parser.process("{2.5*bar*(3-12)}")) == Approx(-45)); } + SECTION("math: min(12, 14)") { REQUIRE(parser.process("{min(12, 14)}") == "12"); } + SECTION("math: max(12, 14)") { REQUIRE(parser.process("{max(12, 14)}") == "14"); } + SECTION("math: min(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{min(13.4, -1238.1)}")) == Approx(-1238.1)); } + SECTION("math: max(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{max(13.4, -1238.1)}")) == Approx(13.4)); } +// SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); } + + // Test the boolean expression parser. + auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); }; + + SECTION("boolean expression parser: 12 == 12") { REQUIRE(boolean_expression("12 == 12")); } + SECTION("boolean expression parser: 12 != 12") { REQUIRE(! boolean_expression("12 != 12")); } + SECTION("boolean expression parser: regex matches") { REQUIRE(boolean_expression("\"has some PATTERN embedded\" =~ /.*PATTERN.*/")); } + SECTION("boolean expression parser: regex does not match") { REQUIRE(! boolean_expression("\"has some PATTERN embedded\" =~ /.*PTRN.*/")); } + SECTION("boolean expression parser: accessing variables, equal") { REQUIRE(boolean_expression("foo + 2 == bar")); } + SECTION("boolean expression parser: accessing variables, not equal") { REQUIRE(! boolean_expression("foo + 3 == bar")); } + SECTION("boolean expression parser: (12 == 12) and (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) and (13 != 14)")); } + SECTION("boolean expression parser: (12 == 12) && (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) && (13 != 14)")); } + SECTION("boolean expression parser: (12 == 12) or (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) or (13 == 14)")); } + SECTION("boolean expression parser: (12 == 12) || (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) || (13 == 14)")); } + SECTION("boolean expression parser: (12 == 12) and not (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) and not (13 == 14)")); } + SECTION("boolean expression parser: ternary true") { REQUIRE(boolean_expression("(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)")); } + SECTION("boolean expression parser: ternary false") { REQUIRE(! boolean_expression("(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)")); } + SECTION("boolean expression parser: ternary false 2") { REQUIRE(boolean_expression("(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)")); } + SECTION("boolean expression parser: ternary true 2") { REQUIRE(! boolean_expression("(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)")); } + SECTION("boolean expression parser: lower than - false") { REQUIRE(! boolean_expression("12 < 3")); } + SECTION("boolean expression parser: lower than - true") { REQUIRE(boolean_expression("12 < 22")); } + SECTION("boolean expression parser: greater than - true") { REQUIRE(boolean_expression("12 > 3")); } + SECTION("boolean expression parser: greater than - false") { REQUIRE(! boolean_expression("12 > 22")); } + SECTION("boolean expression parser: lower than or equal- false") { REQUIRE(! boolean_expression("12 <= 3")); } + SECTION("boolean expression parser: lower than or equal - true") { REQUIRE(boolean_expression("12 <= 22")); } + SECTION("boolean expression parser: greater than or equal - true") { REQUIRE(boolean_expression("12 >= 3")); } + SECTION("boolean expression parser: greater than or equal - false") { REQUIRE(! boolean_expression("12 >= 22")); } + SECTION("boolean expression parser: lower than or equal (same values) - true") { REQUIRE(boolean_expression("12 <= 12")); } + SECTION("boolean expression parser: greater than or equal (same values) - true") { REQUIRE(boolean_expression("12 >= 12")); } + SECTION("complex expression") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1")); } + SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); } + SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); } +}