diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 765c8b8c11..dcd4d2ab11 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -601,6 +601,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) this->apply_print_config(print.config()); this->set_extruders(print.extruders()); + // Initialize colorprint. + m_colorprint_heights = cast(print.config().colorprint_heights.values); + // Initialize autospeed. { // get the minimum cross-section used in the print @@ -1319,6 +1322,18 @@ 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; + while (!m_colorprint_heights.empty() && m_colorprint_heights.front()-EPSILON < layer.print_z) { + m_colorprint_heights.erase(m_colorprint_heights.begin()); + colorprint_change = true; + } + if (colorprint_change) + gcode += "M600\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 = diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 45f17a68ae..bf65311db4 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -317,6 +317,9 @@ protected: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; + // Layer heights for colorprint - updated before the export and erased during the process + // so no toolchange occurs twice. + std::vector m_colorprint_heights; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index d1a942f3f6..41e5f067d6 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -124,6 +124,7 @@ bool Print::invalidate_state_by_config_options(const std::vectormode = comExpert; def->default_value = new ConfigOptionBool(false); + def = this->add("colorprint_heights", coFloats); + def->label = L("Colorprint height"); + def->tooltip = L("Heights at which a filament change is to occur. "); + def->cli = "colorprint-heights=f@"; + def->default_value = new ConfigOptionFloats { }; + def = this->add("compatible_printers", coStrings); def->label = L("Compatible printers"); def->mode = comAdvanced; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d92b3758dd..87a882c641 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -704,6 +704,7 @@ public: ConfigOptionInts bridge_fan_speed; ConfigOptionFloat brim_width; ConfigOptionBool complete_objects; + ConfigOptionFloats colorprint_heights; ConfigOptionBools cooling; ConfigOptionFloat default_acceleration; ConfigOptionInts disable_fan_first_layers; @@ -781,6 +782,7 @@ protected: OPT_PTR(bridge_fan_speed); OPT_PTR(brim_width); OPT_PTR(complete_objects); + OPT_PTR(colorprint_heights); OPT_PTR(cooling); OPT_PTR(default_acceleration); OPT_PTR(disable_fan_first_layers); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 5618eab043..78f8b7462c 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -1,5 +1,6 @@ #include "../../libslic3r/libslic3r.h" #include "GUI_Preview.hpp" +#include "GUI_App.hpp" #include "GUI.hpp" #include "AppConfig.hpp" #include "3DScene.hpp" @@ -22,6 +23,7 @@ namespace Slic3r { namespace GUI { + Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) : m_canvas(nullptr) , m_double_slider_sizer(nullptr) @@ -482,6 +484,11 @@ void Preview::create_double_slider() if (IsShown()) m_canvas->Refresh(); }); + + Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { + auto& config = wxGetApp().preset_bundle->project_config; + ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); + }); } void Preview::update_double_slider(bool force_sliders_full_range) @@ -495,6 +502,11 @@ void Preview::update_double_slider(bool force_sliders_full_range) m_slider->SetMaxValue(layers_z.size() - 1); m_slider->SetSliderValues(values); + const auto& config = wxGetApp().preset_bundle->project_config; + const std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + + m_slider->SetTicksValues(ticks_from_config); + set_double_slider_thumbs(force_sliders_full_range, layers_z, z_low, z_high); } @@ -515,6 +527,15 @@ void Preview::fill_slider_values(std::vector> &values, break; } } + + // All ticks that would end up outside the slider range should be erased. + // TODO: this should probably be placed into more appropriate part of code, + // this way it relies on the Preview tab being active. + auto& config = wxGetApp().preset_bundle->project_config; + std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(), + [values](double val) { return values.back().second < val; }), + ticks_from_config.end()); } void Preview::set_double_slider_thumbs(const bool force_sliders_full_range, diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f22299b7ca..5e42501b66 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -36,6 +36,7 @@ namespace Slic3r { static std::vector s_project_options { + "colorprint_heights", "wiping_volumes_extruders", "wiping_volumes_matrix" }; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index cd6cf171fd..52b6a01e9e 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -11,6 +11,8 @@ #include "GUI_ObjectList.hpp" #include "Model.hpp" +wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); + wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const std::string& icon, wxEvtHandler* event_handler) { @@ -1189,7 +1191,6 @@ wxSize PrusaBitmapTextRenderer::GetSize() const // ---------------------------------------------------------------------------- // PrusaDoubleSlider // ---------------------------------------------------------------------------- - PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, wxWindowID id, int lowerValue, @@ -1371,6 +1372,34 @@ double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) cons return m_values[selection == ssLower ? m_lower_value : m_higher_value].second; } +std::vector PrusaDoubleSlider::GetTicksValues() const +{ + std::vector values; + + if (!m_values.empty()) + for (auto tick : m_ticks) + values.push_back(m_values[tick].second); + + return values; +} + +void PrusaDoubleSlider::SetTicksValues(const std::vector& heights) +{ + if (m_values.empty()) + return; + + m_ticks.clear(); + unsigned int i = 0; + for (auto h : heights) { + while (i < m_values.size() && m_values[i].second - 1e-6 < h) + ++i; + if (i == m_values.size()) + return; + m_ticks.insert(i); + } + +} + void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos) { const double step = get_scroll_step(); @@ -1795,10 +1824,13 @@ void PrusaDoubleSlider::action_tick(const TicksAction action) m_ticks.insert(tick); else if (it != m_ticks.end() && action == taDel) m_ticks.erase(tick); - else + else { + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); return; + } } + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); Update(); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 6293fb9628..e5e4600da7 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -622,6 +622,9 @@ private: // PrusaDoubleSlider // ---------------------------------------------------------------------------- +// custom message the slider sends to its parent to notify a tick-change: +wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); + enum SelectedSlider { ssUndef, ssLower, @@ -632,6 +635,7 @@ enum TicksAction{ taAdd, taDel }; + class PrusaDoubleSlider : public wxControl { public: @@ -669,6 +673,8 @@ public: m_values = values; } void ChangeOneLayerLock(); + std::vector GetTicksValues() const; + void SetTicksValues(const std::vector& heights); void OnPaint(wxPaintEvent& ) { render();} void OnLeftDown(wxMouseEvent& event);