From a62ad3323f389e3ce93915b7fea92bd1eccf321e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 28 Feb 2018 16:04:56 +0100 Subject: First naive implementation of wipe tower settings dialog --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 65 ++----- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 152 +++++++++++++++- xs/src/libslic3r/Print.cpp | 4 +- xs/src/libslic3r/PrintConfig.cpp | 9 +- xs/src/libslic3r/PrintConfig.hpp | 2 + xs/src/slic3r/GUI/BedShapeDialog.cpp | 2 +- xs/src/slic3r/GUI/Preset.cpp | 6 +- xs/src/slic3r/GUI/RammingChart.cpp | 273 ++++++++++++++++++++++++++++ xs/src/slic3r/GUI/RammingChart.hpp | 129 +++++++++++++ xs/src/slic3r/GUI/Tab.cpp | 24 +++ xs/src/slic3r/GUI/Tab.hpp | 1 + xs/src/slic3r/GUI/WipeTowerDialog.cpp | 264 +++++++++++++++++++++++++++ xs/src/slic3r/GUI/WipeTowerDialog.hpp | 115 ++++++++++++ 13 files changed, 991 insertions(+), 55 deletions(-) create mode 100644 xs/src/slic3r/GUI/RammingChart.cpp create mode 100644 xs/src/slic3r/GUI/RammingChart.hpp create mode 100644 xs/src/slic3r/GUI/WipeTowerDialog.cpp create mode 100644 xs/src/slic3r/GUI/WipeTowerDialog.hpp (limited to 'xs/src') diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 2a78ed6f1..d7492fdbb 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -33,33 +33,6 @@ TODO LIST constexpr bool peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet constexpr float min_layer_difference = 2*m_perimeter_width; -constexpr float max_bridge_distance = 10.f; // in mm -constexpr bool improve_first_layer_adhesion = true; -// experimental: ramming speed (mm^3/s) sampled in 0.25s intervals (one filament so far) -const std::vector ramming_speed = {7.6, 7.6, 7.6, 7.6, 9.0, 9.0, 9.0, 10.7, 10.7, 10.7}; -constexpr float ramming_step_multiplicator = 1.2f; // extra spacing may be needed for some materials -constexpr float ramming_line_width_multiplicator = 1.5f; - -// experimental: time requested for cooling in seconds (common for all materials so far) -constexpr float cooling_time = 14; // PVA: 20; SCAFF: 17; PLA+others: 14 - - -// volumes in mm^3 required for wipe: {{from 0 to ...},{from 1 to ...},{from 2 to ...},{from 3 to ...}}, usage [from][to] -const std::vector> wipe_volumes = {{ 0,120, 10, 50}, - { 20, 0, 30, 40}, - { 90, 20, 0, 85}, - {100,140, 30, 0}}; - -/*const std::vector> wipe_volumes = {{0, 67, 67, 67}, - {67, 0, 67, 67}, - {67, 67, 0, 67}, - {67, 67, 67, 0}}; -*/ -/*const std::vector> wipe_volumes = {{0, 10, 10, 10}, - {10, 0, 10, 10}, - {10, 10, 0, 10}, - {10, 10, 10, 0}}; -*/ namespace Slic3r { @@ -614,7 +587,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo { for (const auto &b : m_layer_info->tool_changes) if ( b.new_tool == tool ) { - wipe_volume = wipe_volumes[b.old_tool][b.new_tool]; + wipe_volume = m_par.wipe_volumes[b.old_tool][b.new_tool]; if (tool == m_layer_info->tool_changes.back().new_tool) last_change_in_layer = true; wipe_area = b.required_depth * m_layer_info->extra_spacing; @@ -804,20 +777,20 @@ void WipeTowerPrusaMM::toolchange_Unload( writer.append("; CP TOOLCHANGE UNLOAD\n"); - const float line_width = m_line_width * ramming_line_width_multiplicator; // desired ramming line thickness - const float y_step = line_width * ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm + const float line_width = m_line_width * m_par.ramming_line_width_multiplicator[m_current_tool]; // desired ramming line thickness + const float y_step = line_width * m_par.ramming_step_multiplicator[m_current_tool] * m_extra_spacing; // spacing between lines in mm unsigned i = 0; // iterates through ramming_speed m_left_to_right = true; // current direction of ramming float remaining = xr - xl ; // keeps track of distance to the next turnaround float e_done = 0; // measures E move done from each segment - + writer.travel(xl, cleaning_box.ld.y + m_depth_traversed + y_step/2.f ); // move to starting position - while (i < ramming_speed.size()) + while (i < m_par.ramming_speed[m_current_tool].size()) { - const float x = volume_to_length(ramming_speed[i] * 0.25f, line_width, m_layer_height); - const float e = ramming_speed[i] * 0.25f / Filament_Area; // transform volume per sec to E move; + const float x = volume_to_length(m_par.ramming_speed[m_current_tool][i] * 0.25f, line_width, m_layer_height); + const float e = m_par.ramming_speed[m_current_tool][i] * 0.25f / Filament_Area; // transform volume per sec to E move; const float dist = std::min(x - e_done, remaining); // distance to travel for either the next 0.25s, or to the next turnaround const float actual_time = dist/x * 0.25; writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0, 0, e * (dist / x), std::hypot(dist, e * (dist / x)) / (actual_time / 60.)); @@ -880,21 +853,21 @@ void WipeTowerPrusaMM::toolchange_Unload( const float start_x = writer.x(); const float turning_point = ( xr-start_x > start_x-xl ? xr : xl ); const float max_x_dist = 2*std::abs(start_x-turning_point); - const int N = 4 + (cooling_time-14)/3; - float time = cooling_time / N; - + const unsigned int N = 4 + std::max(0,(m_par.cooling_time[m_current_tool]-14)/3); + float time = m_par.cooling_time[m_current_tool] / N; + i = 0; - while (i #include #include +#include #include #include "WipeTower.hpp" @@ -22,6 +23,11 @@ constexpr float m_perimeter_width = Nozzle_Diameter * Width_To_Nozzle_Ratio * Ko constexpr float WT_EPSILON = 1e-3f; + + + + + namespace Slic3r { @@ -29,6 +35,141 @@ namespace PrusaMultiMaterial { class Writer; }; + + +// Operator overload to output std::pairs +template +std::ostream& operator<<(std::ostream& stream,const std::pair& pair) { + return stream << pair.first << " " << pair.second; +} + +// Operator overload to output elements of a vector to std::ofstream easily: +template +std::ostream& operator<<(std::ostream& stream,const std::vector& vect) { + for (const auto& element : vect) + stream << element << " "; + return stream; +} + +// Operator overload to input elements of a vector from std::ifstream easily (reads until a fail) +template +std::istream& operator>>(std::istream& stream, std::vector& vect) { + vect.clear(); + T value{}; + bool we_read_something = false; + while (stream >> value) { + vect.push_back(value); + we_read_something = true; + } + if (!stream.eof() && we_read_something) { // if this is not eof, we might be at separator - let's get rid of it + stream.clear(); // if we failed on very first line or reached eof, return stream in !good() state + stream.get(); // get() whatever we are stuck at + } + return stream; +} + + +// This struct is used to store parameters and to pass it to wipe tower generator +struct WipeTowerParameters { + WipeTowerParameters() { } // create new empty object + WipeTowerParameters(const std::string& init_data) { // create object and initialize from std::string + std::istringstream in(init_data); // validation of input is left to the caller + in >> bridging >> adhesion >> sampling; + for (std::vector vect{} ; in >> vect ;) { // until we get to fail state ("**")... + if (vect.size()>=3) { + cooling_time.push_back(vect[0]); + ramming_line_width_multiplicator.push_back(vect[1]); + ramming_step_multiplicator.push_back(vect[2]); + vect.erase(vect.begin(),vect.begin()+3); + } + else vect.clear(); // something's not right, we will restore defaults anyway + ramming_speed.push_back(vect); + + if (in.good()) { + in >> vect; + std::vector> pairs; + for (unsigned int i=0;i vect{} ; in >> vect ;) { // let's keep reading + wipe_volumes.push_back(vect); + } + in.clear(); + in.get(); + + std::vector vect{}; + in >> vect; + for (unsigned int i=0;i{7.6, 7.6, 7.6, 7.6, 9.0, 9.0, 9.0, 10.7, 10.7, 10.7}); + ramming_buttons.push_back(std::vector>{{0.05, 6.6},{0.45, 6.8},{0.95, 7.8},{1.45, 8.3},{1.95, 9.7},{2.45,10},{2.95, 7.6},{3.45, 7.6},{3.95, 7.6},{4.45, 7.6},{4.95, 7.6}}); + } + wipe_volumes = {{ 0, 60, 60, 60}, + { 60, 0, 60, 60}, + { 60, 60, 0, 60}, + { 60, 60, 60, 0}}; + filament_wipe_volumes = {{30,30},{30,30},{30,30},{30,30}}; + } + + int bridging = 0.f; + bool adhesion = false; + float sampling = 0.25f; // this does not quite work yet, keep it fixed to 0.25f + std::vector cooling_time; + std::vector ramming_line_width_multiplicator; + std::vector ramming_step_multiplicator; + std::vector> ramming_speed; + std::vector>> ramming_buttons; + std::vector> wipe_volumes; + std::vector> filament_wipe_volumes; +}; + + class WipeTowerPrusaMM : public WipeTower { public: @@ -53,15 +194,16 @@ public: // y -- y coordinates of wipe tower in mm ( left bottom corner ) // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) // wipe_area -- space available for one toolchange in mm - WipeTowerPrusaMM(float x, float y, float width, float wipe_area, float rotation_angle, unsigned int initial_tool) : + WipeTowerPrusaMM(float x, float y, float width, float wipe_area, float rotation_angle, unsigned int initial_tool,std::string& parameters) : m_wipe_tower_pos(x, y), m_wipe_tower_width(width), m_wipe_tower_rotation_angle(rotation_angle), m_y_shift(0.f), m_z_pos(0.f), m_is_first_layer(false), - m_is_last_layer(false), - m_current_tool(initial_tool) + m_is_last_layer(false), + m_current_tool(initial_tool), + m_par(parameters) { for (size_t i = 0; i < 4; ++ i) { // Extruder specific parameters. @@ -206,6 +348,7 @@ private: // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; unsigned int m_current_tool = 0; + WipeTowerParameters m_par; float m_depth_traversed = 0.f; // Current y position at the wipe tower. // How much to wipe the 1st extruder over the wipe tower at the 1st layer @@ -310,6 +453,9 @@ private: float wipe_volume); }; + + + }; // namespace Slic3r #endif /* WipeTowerPrusaMM_hpp_ */ diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 1c63dbf60..fe98612cf 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -187,6 +187,7 @@ bool Print::invalidate_state_by_config_options(const std::vectorconfig.wipe_tower_x.value), float(this->config.wipe_tower_y.value), float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value), - float(this->config.wipe_tower_rotation_angle.value), m_tool_ordering.first_extruder()); + float(this->config.wipe_tower_rotation_angle.value), m_tool_ordering.first_extruder(), + this->config.wipe_tower_advanced.value); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 995dcee99..7a48b3a32 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1701,6 +1701,13 @@ PrintConfigDef::PrintConfigDef() def->cli = "wipe-tower!"; def->default_value = new ConfigOptionBool(false); + def = this->add("wipe_tower_advanced", coString); + def->label = _L("Advanced string"); + def->tooltip = _L("Advanced tooltip "); + def->sidetext = _L("advanced sidetext"); + def->cli = "wipe-tower-advanced=s"; + def->default_value = new ConfigOptionString(""); + def = this->add("wipe_tower_x", coFloat); def->label = _L("Position X"); def->tooltip = _L("X coordinate of the left front corner of a wipe tower"); @@ -1723,7 +1730,7 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionFloat(60.); def = this->add("wipe_tower_per_color_wipe", coFloat); - def->label = _L("Per color change depth"); + def->label = "(Unused and will be likely removed)";//_L("Per color change depth"); def->tooltip = _L("Depth of a wipe color per color change. For N colors, there will be " "maximum (N-1) tool switches performed, therefore the total depth " "of the wipe tower will be (N-1) times this value."); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 7c2d40458..d55aafed6 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -605,6 +605,7 @@ public: ConfigOptionInt threads; ConfigOptionBools wipe; ConfigOptionBool wipe_tower; + ConfigOptionString wipe_tower_advanced; ConfigOptionFloat wipe_tower_x; ConfigOptionFloat wipe_tower_y; ConfigOptionFloat wipe_tower_width; @@ -670,6 +671,7 @@ protected: OPT_PTR(threads); OPT_PTR(wipe); OPT_PTR(wipe_tower); + OPT_PTR(wipe_tower_advanced); OPT_PTR(wipe_tower_x); OPT_PTR(wipe_tower_y); OPT_PTR(wipe_tower_width); diff --git a/xs/src/slic3r/GUI/BedShapeDialog.cpp b/xs/src/slic3r/GUI/BedShapeDialog.cpp index 5ee0c1f8b..8e7f57241 100644 --- a/xs/src/slic3r/GUI/BedShapeDialog.cpp +++ b/xs/src/slic3r/GUI/BedShapeDialog.cpp @@ -34,7 +34,7 @@ void BedShapeDialog::build_dialog(ConfigOptionPoints* default_pt) void BedShapePanel::build_panel(ConfigOptionPoints* default_pt) { -// on_change(nullptr); +// on_change(nullptr); auto box = new wxStaticBox(this, wxID_ANY, _L("Shape")); auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 4d55f347a..be31c1bd1 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -198,9 +198,9 @@ const std::vector& Preset::print_options() "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", - "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_per_color_wipe", "wipe_tower_rotation_angle", - "compatible_printers", "compatible_printers_condition" + "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower_advanced", "wipe_tower", "wipe_tower_x", + "wipe_tower_y", "wipe_tower_width", "wipe_tower_per_color_wipe", "wipe_tower_rotation_angle", "compatible_printers", + "compatible_printers_condition" }; return s_opts; diff --git a/xs/src/slic3r/GUI/RammingChart.cpp b/xs/src/slic3r/GUI/RammingChart.cpp new file mode 100644 index 000000000..3b5f4e41e --- /dev/null +++ b/xs/src/slic3r/GUI/RammingChart.cpp @@ -0,0 +1,273 @@ +#include +#include "RammingChart.hpp" + + +wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); + + +void Chart::draw(wxDC& dc) { + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(m_rect); + + if (visible_area->m_width < 0.499) { + dc.DrawText("NO RAMMING AT ALL",wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-50,m_rect.GetBottom()-m_rect.GetHeight()/2)); + return; + } + + + if (!m_line_to_draw->empty()) { + for (uint i=0;isize()-2;++i) { + int color = 510*((m_rect.GetBottom()-(*m_line_to_draw)[i])/double(m_rect.GetHeight())); + dc.SetPen( wxPen( wxColor(std::min(255,color),255-std::max(color-255,0),0), 1 ) ); + dc.DrawLine(m_rect.GetLeft()+1+i,(*m_line_to_draw)[i],m_rect.GetLeft()+1+i,m_rect.GetBottom()); + } + dc.SetPen( wxPen( wxColor(0,0,0), 1 ) ); + for (uint i=0;isize()-2;++i) { + if (splines) + dc.DrawLine(m_rect.GetLeft()+i,(*m_line_to_draw)[i],m_rect.GetLeft()+i+1,(*m_line_to_draw)[i+1]); + else { + dc.DrawLine(m_rect.GetLeft()+i,(*m_line_to_draw)[i],m_rect.GetLeft()+i+1,(*m_line_to_draw)[i]); + dc.DrawLine(m_rect.GetLeft()+i+1,(*m_line_to_draw)[i],m_rect.GetLeft()+i+1,(*m_line_to_draw)[i+1]); + } + } + } + + // draw draggable buttons + dc.SetBrush(*wxBLUE_BRUSH); + dc.SetPen( wxPen( wxColor(0,0,0), 1 ) ); + for (auto& button : m_buttons[m_current_extruder]) + //dc.DrawRectangle(math_to_screen(button.get_pos())-wxPoint(side/2.,side/2.), wxSize(side,side)); + dc.DrawCircle(math_to_screen(button.get_pos()),side/2.); + //dc.DrawRectangle(math_to_screen(button.get_pos()-wxPoint2DDouble(0.125,0))-wxPoint(0,5),wxSize(50,10)); + + // draw x-axis: + float last_mark = -10000; + for (float math_x=int(visible_area->m_x*10)/10 ; math_x <= (visible_area->m_x+visible_area->m_width) ; math_x+=0.1) { + int x = math_to_screen(wxPoint2DDouble(math_x,visible_area->m_y)).x; + int y = m_rect.GetBottom(); + if (x-last_mark < 50) continue; + dc.DrawLine(x,y+3,x,y-3); + dc.DrawText(wxString().Format(wxT("%.1f"), math_x),wxPoint(x-10,y+7)); + last_mark = x; + } + + // draw y-axis: + last_mark=10000; + for (int math_y=visible_area->m_y ; math_y <= (visible_area->m_y+visible_area->m_height) ; math_y+=1) { + int y = math_to_screen(wxPoint2DDouble(visible_area->m_x,math_y)).y; + int x = m_rect.GetLeft(); + if (last_mark-y < 50) continue; + dc.DrawLine(x-3,y,x+3,y); + dc.DrawText(wxString()<2) { + m_buttons[m_current_extruder].erase(m_buttons[m_current_extruder].begin()+button_index); + recalculate_line(); + } +} + + + +void Chart::mouse_clicked(wxMouseEvent& event) { + wxPoint point = event.GetPosition(); + int button_index = which_button_is_clicked(point); + if ( button_index != -1) { + m_dragged = &m_buttons[m_current_extruder][button_index]; + m_previous_mouse = point; + } +} + + + +void Chart::mouse_moved(wxMouseEvent& event) { + if (!event.Dragging() || !m_dragged) return; + wxPoint pos = event.GetPosition(); + wxRect rect = m_rect; + rect.Deflate(side/2.); + if (!(rect.Contains(pos))) { // the mouse left chart area + mouse_left_window(event); + return; + } + int delta_x = pos.x - m_previous_mouse.x; + int delta_y = pos.y - m_previous_mouse.y; + m_dragged->move(fixed_x?0:double(delta_x)/m_rect.GetWidth() * visible_area->m_width,-double(delta_y)/m_rect.GetHeight() * visible_area->m_height); + m_previous_mouse = pos; + recalculate_line(); +} + + + +void Chart::mouse_double_clicked(wxMouseEvent& event) { + if (!manual_points_manipulation) + return; + wxPoint point = event.GetPosition(); + if (!m_rect.Contains(point)) // the click is outside the chart + return; + m_buttons[m_current_extruder].push_back(screen_to_math(point)); + std::sort(m_buttons[m_current_extruder].begin(),m_buttons[m_current_extruder].end()); + recalculate_line(); + return; +} + + + + +void Chart::recalculate_line() { + std::vector points; + for (auto& but : m_buttons[m_current_extruder]) { + points.push_back(wxPoint(math_to_screen(but.get_pos()))); + if (points.size()>1 && points.back().x==points[points.size()-2].x) points.pop_back(); + if (points.size()>1 && points.back().x > m_rect.GetRight()) { + points.pop_back(); + break; + } + } + std::sort(points.begin(),points.end(),[](wxPoint& a,wxPoint& b) { return a.x < b.x; }); + + m_line_to_draw->clear(); + m_total_volume = 0.f; + + + // Cubic spline interpolation: see https://en.wikiversity.org/wiki/Cubic_Spline_Interpolation#Methods + const bool boundary_first_derivative = true; // true - first derivative is 0 at the leftmost and rightmost point + // false - second ---- || ------- + const int N = points.size()-1; // last point can be accessed as N, we have N+1 total points + std::vector diag(N+1); + std::vector mu(N+1); + std::vector lambda(N+1); + std::vector h(N+1); + std::vector rhs(N+1); + + // let's fill in inner equations + for (int i=1;i<=N;++i) h[i] = points[i].x-points[i-1].x; + std::fill(diag.begin(),diag.end(),2.f); + for (int i=1;i<=N-1;++i) { + mu[i] = h[i]/(h[i]+h[i+1]); + lambda[i] = 1.f - mu[i]; + rhs[i] = 6 * ( float(points[i+1].y-points[i].y )/(h[i+1]*(points[i+1].x-points[i-1].x)) - + float(points[i].y -points[i-1].y)/(h[i] *(points[i+1].x-points[i-1].x)) ); + } + + // now fill in the first and last equations, according to boundary conditions: + if (boundary_first_derivative) { + const float endpoints_derivative = 0; + lambda[0] = 1; + mu[N] = 1; + rhs[0] = (6.f/h[1]) * (float(points[0].y-points[1].y)/(points[0].x-points[1].x) - endpoints_derivative); + rhs[N] = (6.f/h[N]) * (endpoints_derivative - float(points[N-1].y-points[N].y)/(points[N-1].x-points[N].x)); + } + else { + lambda[0] = 0; + mu[N] = 0; + rhs[0] = 0; + rhs[N] = 0; + } + + // the trilinear system is ready to be solved: + for (int i=1;i<=N;++i) { + float multiple = mu[i]/diag[i-1]; // let's subtract proper multiple of above equation + diag[i]-= multiple * lambda[i-1]; + rhs[i] -= multiple * rhs[i-1]; + } + // now the back substitution (vector mu contains invalid values from now on): + rhs[N] = rhs[N]/diag[N]; + for (int i=N-1;i>=0;--i) + rhs[i] = (rhs[i]-lambda[i]*rhs[i+1])/diag[i]; + + + + + unsigned int i=1; + float y=0.f; + for (int x=m_rect.GetLeft(); x<=m_rect.GetRight() ; ++x) { + if (splines) { + if (i x) + y = points[0].y; + else + if (points[N].x < x) + y = points[N].y; + else + y = (rhs[i-1]*pow(points[i].x-x,3)+rhs[i]*pow(x-points[i-1].x,3)) / (6*h[i]) + + (points[i-1].y-rhs[i-1]*h[i]*h[i]/6.f) * (points[i].x-x)/h[i] + + (points[i].y -rhs[i] *h[i]*h[i]/6.f) * (x-points[i-1].x)/h[i]; + m_line_to_draw->push_back(y); + } + else { + float x_math = screen_to_math(wxPoint(x,0)).m_x; + if (i+2<=points.size() && m_buttons[m_current_extruder][i+1].get_pos().m_x-0.125 < x_math) + ++i; + m_line_to_draw->push_back(math_to_screen(wxPoint2DDouble(x_math,m_buttons[m_current_extruder][i].get_pos().m_y)).y); + } + + + m_line_to_draw->back() = std::max(m_line_to_draw->back(), m_rect.GetTop()-1); + m_line_to_draw->back() = std::min(m_line_to_draw->back(), m_rect.GetBottom()-1); + m_total_volume += (m_rect.GetBottom() - m_line_to_draw->back()) * (visible_area->m_width / m_rect.GetWidth()) * (visible_area->m_height / m_rect.GetHeight()); + } + + wxPostEvent(this->GetParent(), wxCommandEvent(EVT_WIPE_TOWER_CHART_CHANGED)); + Refresh(); +} + + + +std::vector> Chart::get_ramming_speeds(float sampling) const { + std::vector> speeds_out; + for (unsigned int extruder_id = 0;extruder_id this_extruder; + const int number_of_samples = std::round( visible_areas[extruder_id].m_width / sampling); + if (number_of_samples>0) { + const int dx = (m_lines_to_draw[extruder_id].size()-1) / number_of_samples; + for (int j=0;j>> Chart::get_buttons() const { + std::vector>> buttons_out; + for (const auto& ext : m_buttons) { + std::vector> this_extruder; + for (const auto& button : ext) + this_extruder.push_back(std::make_pair(button.get_pos().m_x,button.get_pos().m_y)); + buttons_out.push_back(std::move(this_extruder)); + } + return buttons_out; +} + + + + +BEGIN_EVENT_TABLE(Chart, wxWindow) +EVT_MOTION(Chart::mouse_moved) +EVT_LEFT_DOWN(Chart::mouse_clicked) +EVT_LEFT_UP(Chart::mouse_released) +EVT_LEFT_DCLICK(Chart::mouse_double_clicked) +EVT_RIGHT_DOWN(Chart::mouse_right_button_clicked) +EVT_LEAVE_WINDOW(Chart::mouse_left_window) +EVT_PAINT(Chart::paint_event) +END_EVENT_TABLE() diff --git a/xs/src/slic3r/GUI/RammingChart.hpp b/xs/src/slic3r/GUI/RammingChart.hpp new file mode 100644 index 000000000..5443e957a --- /dev/null +++ b/xs/src/slic3r/GUI/RammingChart.hpp @@ -0,0 +1,129 @@ +#ifndef RAMMING_CHART_H_ +#define RAMMING_CHART_H_ + +#include +#include +#ifndef WX_PRECOMP + #include +#endif + +wxDECLARE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); + + +class Chart : public wxWindow { + +public: + Chart(wxWindow* parent, wxRect rect,const std::vector>>& initial_buttons,std::vector> ramming_speed, float sampling) : + wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize()) + { + m_rect=wxRect(wxPoint(30,0),rect.GetSize()-wxSize(30,30)); + for (int i=0;i<4;++i) { + visible_areas.push_back(wxRect2DDouble(0.0, 0.0, sampling*ramming_speed[i].size(), 20.)); + m_buttons.push_back(std::vector()); + m_lines_to_draw.push_back(std::vector()); + if (initial_buttons.size()>0) + for (const auto& pair : initial_buttons[i]) + m_buttons.back().push_back(wxPoint2DDouble(pair.first,pair.second)); + set_extruder(i); // to calculate all interpolating splines + } + set_extruder(0); + } + void set_extruder(unsigned ext) { + if (ext>=4) return; + m_current_extruder = ext; + visible_area = &(visible_areas[ext]); + m_line_to_draw = &(m_lines_to_draw[ext]); + recalculate_line(); + } + void set_xy_range(float x,float y) { + x = int(x/0.5) * 0.5; + if (x>=0) visible_area->SetRight(x); + if (y>=0) visible_area->SetBottom(y); + recalculate_line(); + } + float get_volume() const { return m_total_volume; } + float get_time() const { return visible_area->m_width; } + std::vector> get_ramming_speeds(float sampling) const; //returns sampled ramming speed for all extruders + std::vector>> get_buttons() const; // returns buttons position for all extruders + + + void draw(wxDC& dc); + + void mouse_clicked(wxMouseEvent& event); + void mouse_right_button_clicked(wxMouseEvent& event); + void mouse_moved(wxMouseEvent& event); + void mouse_double_clicked(wxMouseEvent& event); + void mouse_left_window(wxMouseEvent&) { m_dragged = nullptr; } + void mouse_released(wxMouseEvent&) { m_dragged = nullptr; } + void paint_event(wxPaintEvent&) { wxPaintDC dc(this); draw(dc); } + DECLARE_EVENT_TABLE() + + + +private: + static const bool fixed_x = true; + static const bool splines = true; + static const bool manual_points_manipulation = false; + static const int side = 10; // side of draggable button + + class ButtonToDrag { + public: + bool operator<(ButtonToDrag& a) { return m_pos.m_x < a.m_pos.m_x; } + ButtonToDrag(wxPoint2DDouble pos) : m_pos{pos} {}; + wxPoint2DDouble get_pos() const { return m_pos; } + void move(double x,double y) { m_pos.m_x+=x; m_pos.m_y+=y; } + private: + wxPoint2DDouble m_pos; // position in math coordinates + }; + + + + wxPoint math_to_screen(const wxPoint2DDouble& math) const { + wxPoint screen; + screen.x = (math.m_x-visible_area->m_x) * (m_rect.GetWidth() / visible_area->m_width ); + screen.y = (math.m_y-visible_area->m_y) * (m_rect.GetHeight() / visible_area->m_height ); + screen.y *= -1; + screen += m_rect.GetLeftBottom(); + return screen; + } + wxPoint2DDouble screen_to_math(const wxPoint& screen) const { + wxPoint2DDouble math = screen; + math -= m_rect.GetLeftBottom(); + math.m_y *= -1; + math.m_x *= visible_area->m_width / m_rect.GetWidth(); // scales to [0;1]x[0,1] + math.m_y *= visible_area->m_height / m_rect.GetHeight(); + return (math+visible_area->GetLeftTop()); + } + + int which_button_is_clicked(const wxPoint& point) const { + if (!m_rect.Contains(point)) + return -1; + for (uint i=0;i > m_buttons; + std::vector< std::vector > m_lines_to_draw; + std::vector< wxRect2DDouble > visible_areas; + wxRect2DDouble* visible_area = nullptr; + std::vector* m_line_to_draw = nullptr; + ButtonToDrag* m_dragged = nullptr; + float m_total_volume = 0.f; + + +}; + + +#endif // RAMMING_CHART_H_ \ No newline at end of file diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index ebfa69eb5..7e1ad5dc5 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -3,6 +3,7 @@ #include "PresetBundle.hpp" #include "PresetHints.hpp" #include "../../libslic3r/Utils.hpp" +#include "WipeTowerDialog.hpp" #include #include @@ -440,6 +441,7 @@ void TabPrint::build() optgroup->append_single_option_line("ooze_prevention"); optgroup->append_single_option_line("standby_temperature_delta"); + if (true) { optgroup = page->new_optgroup(_L("Wipe tower")); optgroup->append_single_option_line("wipe_tower"); optgroup->append_single_option_line("wipe_tower_x"); @@ -447,6 +449,27 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_width"); optgroup->append_single_option_line("wipe_tower_per_color_wipe"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); + Line line{ _L("Advanced"), "" }; + line.widget = [this](wxWindow* parent){ + m_wipe_tower_btn = new wxButton(parent, wxID_ANY, _L("Advanced settings")+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(m_wipe_tower_btn); + m_wipe_tower_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) + { + std::string init_data = (m_config->option("wipe_tower_advanced"))->value; + std::cout << "dialog init: " << init_data << std::endl; + WipeTowerDialog dlg(this,init_data); // dlg lives on stack, no need to call Destroy + + if (dlg.ShowModal() == wxID_OK) { + load_key_value("wipe_tower_advanced", dlg.GetValue()); + std::cout << std::endl << "dialog returned: " << dlg.GetValue() << std::endl; + } + })); + return sizer; + }; + optgroup->append_line(line); + } + optgroup = page->new_optgroup(_L("Advanced")); optgroup->append_single_option_line("interface_shells"); @@ -766,6 +789,7 @@ void TabPrint::update() vec_enable = { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_per_color_wipe", "wipe_tower_rotation_angle"}; for (auto el : vec_enable) get_field(el)->toggle(have_wipe_tower); + m_wipe_tower_btn->Enable(have_wipe_tower); m_recommended_thin_wall_thickness_description_line->SetText( PresetHints::recommended_thin_wall_thickness(*m_preset_bundle)); diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index 4f3a15736..b6d273e38 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -90,6 +90,7 @@ protected: wxImageList* m_icons; wxCheckBox* m_compatible_printers_checkbox; wxButton* m_compatible_printers_btn; + wxButton* m_wipe_tower_btn; int m_icon_count; std::map m_icon_index; // Map from an icon file name to its index in $self->{icons}. diff --git a/xs/src/slic3r/GUI/WipeTowerDialog.cpp b/xs/src/slic3r/GUI/WipeTowerDialog.cpp new file mode 100644 index 000000000..5b188e6d1 --- /dev/null +++ b/xs/src/slic3r/GUI/WipeTowerDialog.cpp @@ -0,0 +1,264 @@ +#include "WipeTowerDialog.hpp" + +// Human-readable output of Parameters structure +std::ostream& operator<<(std::ostream& str,Slic3r::WipeTowerParameters& par) { + str << "bridging: " << par.bridging << "\n"; + str << "adhesion: " << par.adhesion << "\n"; + str << "sampling: " << par.sampling << "\n"; + + str << "cooling times: "; + for (const auto& a : par.cooling_time) str << a << " "; + + str << "line widths: "; + for (const auto& a : par.ramming_line_width_multiplicator) str << a << " "; + + str << "line spacing: "; + for (const auto& a : par.ramming_step_multiplicator) str << a << " "; + + str<<"\n\nramming_speeds:\n"; + for (const auto& a : par.ramming_speed) { + for (const auto& b : a) + str << b << " "; + str<<"\n"; + } + str<<"\n\nramming_buttons:\n"; + for (const auto& a : par.ramming_buttons) { + for (const auto& b : a) { + Slic3r::operator <<(str,b); // temporary hack (this << is in the namespace Slic3r) + str << " | "; // the function will be deleted after everything is debugged, anyway + } + str<<"\n"; + } + str<<"\n\nwipe volumes:\n"; + for (const auto& a : par.wipe_volumes) { + for (const auto& b : a) + str << b << " "; + str<<"\n"; + } + str<<"\n\nfilament wipe volumes:\n"; + for (const auto& a : par.filament_wipe_volumes) { + Slic3r::operator <<(str,a); + str << " "; + } + str<<"\n"; + + return str; +} + + + + +RammingPanel::RammingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p) +: wxPanel(parent,wxID_ANY,wxPoint(0,0),wxSize(0,0),wxBORDER_RAISED) +{ + new wxStaticText(this,wxID_ANY,wxString("Total ramming time (s):"), wxPoint(500,105), wxSize(200,25),wxALIGN_LEFT); + m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString, wxPoint(700,100), wxSize(75,25),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0.,5.0,3.,0.5); + new wxStaticText(this,wxID_ANY,wxString("Total rammed volume (mm3):"), wxPoint(500,135), wxSize(200,25),wxALIGN_LEFT); + m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString, wxPoint(700,130), wxSize(75,25),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,10000,0); + new wxStaticText(this,wxID_ANY,wxString("Ramming line width (%):"), wxPoint(500,205), wxSize(200,25),wxALIGN_LEFT); + m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString, wxPoint(700,200), wxSize(75,25),wxSP_ARROW_KEYS|wxALIGN_RIGHT,10,200,100); + new wxStaticText(this,wxID_ANY,wxString("Ramming line spacing (%):"), wxPoint(500,235), wxSize(200,25),wxALIGN_LEFT); + m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString, wxPoint(700,230), wxSize(75,25),wxSP_ARROW_KEYS|wxALIGN_RIGHT,10,200,100); + new wxStaticText(this,wxID_ANY,wxString("Extruder #:"), wxPoint(500,12), wxSize(200,25),wxALIGN_LEFT); + + wxArrayString choices; + for (unsigned int i=0;iset_extruder(0); + m_widget_time->SetValue(m_chart->get_time()); + m_widget_time->SetDigits(2); + m_widget_volume->SetValue(m_chart->get_volume()); + m_widget_volume->Disable(); + m_widget_extruder->SetSelection(0); + extruder_selection_changed(); // tell everyone to redraw + + m_widget_ramming_step_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); + m_widget_ramming_line_width_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); + m_widget_extruder->Bind(wxEVT_CHOICE,[this](wxCommandEvent&) { extruder_selection_changed(); }); + m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);}); + m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); +} + +void RammingPanel::fill_parameters(Slic3r::WipeTowerParameters& p) +{ + if (!m_chart) return; + p.ramming_buttons = m_chart->get_buttons(); + p.ramming_speed = m_chart->get_ramming_speeds(p.sampling); + for (unsigned int i=0;iGetSelection(); + m_chart->set_extruder(m_current_extruder); // tell our chart to redraw + m_widget_ramming_line_width_multiplicator ->SetValue(m_ramming_line_width_multiplicators[m_current_extruder]); + m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicators[m_current_extruder]); +} + +void RammingPanel::line_parameters_changed() { + m_ramming_line_width_multiplicators[m_current_extruder]=m_widget_ramming_line_width_multiplicator->GetValue(); + m_ramming_step_multiplicators[m_current_extruder]=m_widget_ramming_step_multiplicator->GetValue(); +} + + + + + + +CoolingPanel::CoolingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p) +: wxPanel(parent,wxID_ANY,wxPoint(0,0),wxSize(0,0),wxBORDER_RAISED) +{ + new wxStaticText(this,wxID_ANY,wxString("Time (in seconds) reserved for cooling after unload:"),wxPoint(220,50) ,wxSize(400,25),wxALIGN_LEFT); + for (int i=0;i<4;++i) { + new wxStaticText(this,wxID_ANY,wxString("Filament #")<=m_widget_edits.size()) + break; // so we don't initialize non-existent widget + m_widget_edits[i]->SetValue(p.cooling_time[i]); + } +} + +void CoolingPanel::fill_parameters(Slic3r::WipeTowerParameters& p) { + p.cooling_time.clear(); + for (int i=0;i<4;++i) + p.cooling_time.push_back(m_widget_edits[i]->GetValue()); +} + + + +WipingPanel::WipingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p) +: wxPanel(parent,wxID_ANY,wxPoint(0,0),wxSize(0,0),wxBORDER_RAISED) +{ + const int N = 4; // number of extruders + new wxStaticText(this,wxID_ANY,wxString("Volume to wipe when the filament is being"),wxPoint(40,55) ,wxSize(500,25)); + new wxStaticText(this,wxID_ANY,wxString("unloaded"),wxPoint(110,75) ,wxSize(500,25)); + new wxStaticText(this,wxID_ANY,wxString("loaded"),wxPoint(195,75) ,wxSize(500,25)); + m_widget_button = new wxButton(this,wxID_ANY,"-> Fill in the matrix ->",wxPoint(300,130),wxSize(175,50)); + for (int i=0;i(0)); + new wxStaticText(this,wxID_ANY,wxString("")<Disable(); + else + edit_boxes[i][j]->SetValue(wxString("")<Bind(wxEVT_BUTTON,[this](wxCommandEvent&){fill_in_matrix();}); +} + +void WipingPanel::fill_parameters(Slic3r::WipeTowerParameters& p) { + p.wipe_volumes.clear(); + p.filament_wipe_volumes.clear(); + for (int i=0;i<4;++i) { + // first go through the full matrix: + p.wipe_volumes.push_back(std::vector()); + for (int j=0;j<4;++j) { + double val = 0.; + edit_boxes[j][i]->GetValue().ToDouble(&val); + p.wipe_volumes[i].push_back((float)val); + } + + // now the filament volumes: + p.filament_wipe_volumes.push_back(std::make_pair(m_old[i]->GetValue(),m_new[i]->GetValue())); + } +} + +void WipingPanel::fill_in_matrix() { + wxArrayString choices; + choices.Add("sum"); + choices.Add("maximum"); + wxSingleChoiceDialog dialog(this,"How shall I calculate volume for any given pair?\n\nI can either sum volumes for old and new filament, or just use the higher value.","DEBUGGING",choices); + if (dialog.ShowModal() == wxID_CANCEL) + return; + for (unsigned i=0;i<4;++i) { + for (unsigned j=0;j<4;++j) { + if (i==j) continue; + if (!dialog.GetSelection()) edit_boxes[j][i]->SetValue(wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue())); + else + edit_boxes[j][i]->SetValue(wxString("")<< (std::max(m_old[i]->GetValue(), m_new[j]->GetValue()))); + } + } +} + + + +GeneralPanel::GeneralPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p) : wxPanel(parent,wxID_ANY,wxPoint(0,0),wxSize(0,0),wxBORDER_RAISED) { + new wxStaticText(this,wxID_ANY,wxString("Maximum bridging over sparse infill (mm):"),wxPoint(100,105) ,wxSize(280,25),wxALIGN_LEFT); + m_widget_bridge = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxPoint(380,100),wxSize(50,25),wxALIGN_RIGHT|wxSP_ARROW_KEYS,1,50,10); + m_widget_adhesion = new wxCheckBox(this,wxID_ANY,"Increased adhesion of first layer",wxPoint(100,150),wxSize(330,25),wxALIGN_RIGHT); + m_widget_bridge->SetValue(p.bridging); + m_widget_adhesion->SetValue(p.adhesion); +} + +void GeneralPanel::fill_parameters(Slic3r::WipeTowerParameters& p) { + p.bridging = m_widget_bridge->GetValue(); + p.adhesion = m_widget_adhesion->GetValue(); +} + + + + + +WipeTowerDialog::WipeTowerDialog(wxWindow* parent,const std::string& init_data) +: wxDialog(parent, -1, wxT("Wipe tower advanced settings"), wxPoint(50,50), wxSize(800,550), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + this->Centre(); + + Slic3r::WipeTowerParameters parameters(init_data); + if (!parameters.validate()) { + wxMessageDialog(this,"Wipe tower parameters not parsed correctly!\nRestoring default settings.","Error",wxICON_ERROR); + parameters.set_defaults(); + } + + wxNotebook* notebook = new wxNotebook(this,wxID_ANY,wxPoint(0,0),wxSize(800,450)); + + m_panel_general = new GeneralPanel(notebook,parameters); + m_panel_ramming = new RammingPanel(notebook,parameters); + m_panel_cooling = new CoolingPanel(notebook,parameters); + m_panel_wiping = new WipingPanel(notebook,parameters); + notebook->AddPage(m_panel_general,"General"); + notebook->AddPage(m_panel_ramming,"Ramming"); + notebook->AddPage(m_panel_cooling,"Cooling"); + notebook->AddPage(m_panel_wiping,"Wiping"); + this->Show(); + + auto main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(notebook, 1, wxEXPAND); + main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); + SetSizer(main_sizer); + SetMinSize(GetSize()); + main_sizer->SetSizeHints(this); + + this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); }); + + this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { + m_output_data=read_dialog_values(); + EndModal(wxID_OK); + },wxID_OK); +} + diff --git a/xs/src/slic3r/GUI/WipeTowerDialog.hpp b/xs/src/slic3r/GUI/WipeTowerDialog.hpp new file mode 100644 index 000000000..452886bc3 --- /dev/null +++ b/xs/src/slic3r/GUI/WipeTowerDialog.hpp @@ -0,0 +1,115 @@ +#ifndef _WIPE_TOWER_DIALOG_H_ +#define _WIPE_TOWER_DIALOG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "../../libslic3r/GCode/WipeTowerPrusaMM.hpp" +#include "RammingChart.hpp" + + +// Human-readable output of Parameters structure +std::ostream& operator<<(std::ostream& str,Slic3r::WipeTowerParameters& par); + + +class RammingPanel : public wxPanel { +public: + RammingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p); + void fill_parameters(Slic3r::WipeTowerParameters& p); + +private: + Chart* m_chart = nullptr; + wxSpinCtrl* m_widget_volume = nullptr; + wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr; + wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr; + wxSpinCtrlDouble* m_widget_time = nullptr; + wxChoice* m_widget_extruder = nullptr; + std::vector m_ramming_step_multiplicators; + std::vector m_ramming_line_width_multiplicators; + int m_current_extruder = 0; // zero-based index + + void extruder_selection_changed(); + + void line_parameters_changed(); +}; + + + + + + +class CoolingPanel : public wxPanel { +public: + CoolingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p); + void fill_parameters(Slic3r::WipeTowerParameters& p); + +private: + std::vector m_widget_edits; +}; + + + + + + +class WipingPanel : public wxPanel { +public: + WipingPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p); + void fill_parameters(Slic3r::WipeTowerParameters& p); + +private: + void fill_in_matrix(); + + std::vector m_old; + std::vector m_new; + std::vector> edit_boxes; + wxButton* m_widget_button=nullptr; +}; + + + + +class GeneralPanel : public wxPanel { +public: + GeneralPanel(wxWindow* parent,const Slic3r::WipeTowerParameters& p); + void fill_parameters(Slic3r::WipeTowerParameters& p); + +private: + wxSpinCtrl* m_widget_bridge; + wxCheckBox* m_widget_adhesion; +}; + + + + +class WipeTowerDialog : public wxDialog { +public: + WipeTowerDialog(wxWindow* parent,const std::string& init_data); + + std::string GetValue() const { return m_output_data; } + + +private: + std::string m_file_name="config_wipe_tower"; + GeneralPanel* m_panel_general = nullptr; + RammingPanel* m_panel_ramming = nullptr; + CoolingPanel* m_panel_cooling = nullptr; + WipingPanel* m_panel_wiping = nullptr; + std::string m_output_data = ""; + + std::string read_dialog_values() { + Slic3r::WipeTowerParameters p; + m_panel_general->fill_parameters(p); + m_panel_ramming->fill_parameters(p); + m_panel_cooling->fill_parameters(p); + m_panel_wiping ->fill_parameters(p); + return p.to_string(); + } +}; + +#endif // _WIPE_TOWER_DIALOG_H_ \ No newline at end of file -- cgit v1.2.3