diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 4148745f88..93d94b016c 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -412,7 +412,8 @@ struct SLAPrintStatistics size_t fast_layers_count; double total_cost; double total_weight; - std::vector layers_times; + std::vector layers_times_running_total; + std::vector layers_areas; // Config with the filled in print statistics. DynamicConfig config() const; @@ -429,7 +430,8 @@ struct SLAPrintStatistics fast_layers_count = 0; total_cost = 0.; total_weight = 0.; - layers_times.clear(); + layers_times_running_total.clear(); + layers_areas.clear(); } }; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 4b67975a87..bc792e1f42 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -942,8 +942,10 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { double models_volume(0.0); double estim_time(0.0); - std::vector layers_times; + std::vector> layers_times; // level and time + std::vector> layers_areas; // level and area layers_times.reserve(printer_input.size()); + layers_areas.reserve(printer_input.size()); size_t slow_layers = 0; size_t fast_layers = 0; @@ -961,7 +963,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { // write vars &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, - &fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt) + &fast_layers, &fade_layer_time, &layers_times, &layers_areas](size_t sliced_layer_cnt) { PrintLayer &layer = m_print->m_printer_input[sliced_layer_cnt]; @@ -1029,6 +1031,8 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { Lock lck(mutex); supports_volume += layer_support_area * l_height; } + double layer_area = layer_model_area + layer_support_area; + // Here we can save the expensively calculated polygons for printing ExPolygons trslices; trslices.reserve(model_polygons.size() + supports_polygons.size()); @@ -1039,7 +1043,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { // Calculation of the slow and fast layers to the future controlling those values on FW - const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; + const bool is_fast_layer = layer_area <= display_area*area_fill; const double tilt_time = material_config.material_print_speed == slamsSlow ? slow_tilt : material_config.material_print_speed == slamsHighViscosity ? hv_tilt : is_fast_layer ? fast_tilt : slow_tilt; @@ -1082,13 +1086,14 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { + 120 / 1000 // Magical constant to compensate remaining computation delay in exposure thread ); - layers_times.push_back(layer_times); + layers_times.emplace_back(layer.level(), layer_times); estim_time += layer_times; + layers_areas.emplace_back(layer.level(), layer_area * SCALING_FACTOR * SCALING_FACTOR); } }; // sequential version for debugging: - // for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); + // for(size_t i = 0; i < printer_input.size(); ++i) printlayerfn(i); execution::for_each(ex_tbb, size_t(0), printer_input.size(), printlayerfn, execution::max_concurrency(ex_tbb)); @@ -1102,7 +1107,17 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { print_statistics.estimated_print_time = NaNd; else { print_statistics.estimated_print_time = estim_time; - print_statistics.layers_times = layers_times; + + // Times and areas vectors were filled in parallel, they need to be sorted first. + // The print statistics will contain only the values (in the correct order). + std::sort(layers_times.begin(), layers_times.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); + std::sort(layers_areas.begin(), layers_areas.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); + print_statistics.layers_times_running_total.clear(); + for (size_t i=0; i& areas = print.print_statistics().layers_areas; + const std::vector& times = print.print_statistics().layers_times_running_total; + const double display_area = print.printer_config().display_height * print.printer_config().display_width; + if (layer_idx >= 0 && layer_idx < areas.size()) { + const double area = areas[layer_idx]; + const double time = times[layer_idx] - (layer_idx == 0 ? 0. : times[layer_idx-1]); + const double time_until_layer = times[layer_idx]; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.set_next_window_pos(float(cnv_width) - imgui.get_style_scaling() * 5.f, imgui.get_style_scaling() * 55.f, ImGuiCond_Always, 1.0f, 0.0f); + ImGui::SetNextWindowBgAlpha(0.6f); + + imgui.begin(_u8L("Layer statistics"), ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoFocusOnAppearing); + ImGui::Text(_u8L("Layer area: %.0f mm²").c_str(), area); + int area_percent_int = int(std::round(100. * area/display_area)); + ImGui::Text(GUI::format(_u8L("Area fill: %1% %%%%"), area_percent_int == 0 ? "<1" : std::to_string(area_percent_int)).c_str()); + ImGui::Separator(); + ImGui::Text(GUI::format(_u8L("Layer time: %1%"), get_time_dhms(time)).c_str()); + std::string buffer_str = _u8L("Time since start: %1%"); + ImGui::Text(GUI::format(buffer_str, get_time_dhms(time_until_layer)).c_str()); + + // The dummy control below uses the assumption that the total time string will be the longest + // and forces the width of the window large enough so it does not resize depending on the current value. + ImGui::Dummy(ImVec2(ImGui::CalcTextSize(GUI::format(buffer_str, get_time_dhms(82799)).c_str()).x, 0.)); + imgui.end(); + } +} + + + void GLCanvas3D::_render_sla_slices() { if (!m_use_clipping_planes || current_printer_technology() != ptSLA) @@ -6533,6 +6567,11 @@ void GLCanvas3D::_render_sla_slices() // nothing to render, return return; + if (print->finished()) { + double slider_width = 0.; + render_sla_layer_legend(*print, m_layer_slider_index, get_canvas_size().get_width()); + } + double clip_min_z = -m_clipping_planes[0].get_data()[3]; double clip_max_z = m_clipping_planes[1].get_data()[3]; for (unsigned int i = 0; i < (unsigned int)print_objects.size(); ++i) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0660ca7cc9..5e9e24a88f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -504,6 +504,7 @@ private: ClippingPlane m_camera_clipping_plane; bool m_use_clipping_planes; std::array m_sla_caps; + int m_layer_slider_index = -1; std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() @@ -757,6 +758,8 @@ public: void bed_shape_changed(); + void set_layer_slider_index(int i) { m_layer_slider_index = i; } + void set_clipping_plane(unsigned int id, const ClippingPlane& plane) { if (id < 2) { m_clipping_planes[id] = plane; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 5eb32a6474..33b7daa63f 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -362,16 +362,6 @@ void Preview::sys_color_changed() m_layers_slider->sys_color_changed(); } -void Preview::jump_layers_slider(wxKeyEvent& evt) -{ - if (m_layers_slider) m_layers_slider->OnChar(evt); -} - -void Preview::move_layers_slider(wxKeyEvent& evt) -{ - if (m_layers_slider != nullptr) m_layers_slider->OnKeyDown(evt); -} - void Preview::edit_layers_slider(wxKeyEvent& evt) { if (m_layers_slider != nullptr) m_layers_slider->OnChar(evt); @@ -539,7 +529,7 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects"); m_layers_slider->SetDrawMode(sla_print_technology, sequential_print); if (sla_print_technology) - m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times); + m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times_running_total); else { auto print_mode_stat = m_gcode_result->print_statistics.modes.front(); m_layers_slider->SetLayersTimes(print_mode_stat.layers_times, print_mode_stat.time); @@ -907,6 +897,16 @@ void Preview::load_print_as_sla() } } +void Preview::jump_layers_slider(wxKeyEvent& evt) +{ + if (m_layers_slider) m_layers_slider->OnChar(evt); +} + +void Preview::move_layers_slider(wxKeyEvent& evt) +{ + if (m_layers_slider != nullptr) m_layers_slider->OnKeyDown(evt); +} + void Preview::on_layers_slider_scroll_changed(wxCommandEvent& event) { if (IsShown()) { @@ -919,6 +919,7 @@ void Preview::on_layers_slider_scroll_changed(wxCommandEvent& event) else if (tech == ptSLA) { m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValueD())); m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValueD())); + m_canvas->set_layer_slider_index(m_layers_slider->GetHigherValue()); m_canvas->render(); } } diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index eb4bfbe846..9d37b16b4f 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -147,6 +147,7 @@ public: void move_layers_slider(wxKeyEvent& evt); void edit_layers_slider(wxKeyEvent& evt); + bool is_loaded() const { return m_loaded; } void update_moves_slider(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index a4df3bc66d..0b0e5d1ed7 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5430,7 +5430,7 @@ void TabSLAMaterial::build_tilt_group(Slic3r::GUI::PageShp page) create_legend(page, legend_columns, comExpert, true); auto optgroup = page->new_optgroup(L("Tilt profiles")); - optgroup->on_change = [this, optgroup](const t_config_option_key& key, boost::any value) + optgroup->m_on_change = [this, optgroup](const t_config_option_key& key, boost::any value) { if (key.find_first_of("use_tilt") == 0) toggle_tilt_options(key == "use_tilt#0");