diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 7f8efc53f..67ed7c699 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -163,6 +163,7 @@ void GCodeProcessor::TimeMachine::reset() gcode_time.reset(); blocks = std::vector(); std::fill(moves_time.begin(), moves_time.end(), 0.0f); + std::fill(roles_time.begin(), roles_time.end(), 0.0f); } void GCodeProcessor::TimeMachine::simulate_st_synchronize(float additional_time) @@ -271,6 +272,7 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks) time += block_time; gcode_time.cache += block_time; moves_time[static_cast(block.move_type)] += block_time; + roles_time[static_cast(block.role)] += block_time; // if (block.g1_line_id >= 0) // m_g1_times.emplace_back(block.g1_line_id, time); @@ -397,15 +399,18 @@ void GCodeProcessor::update_print_stats_estimated_times(PrintStatistics& print_s print_statistics.estimated_normal_print_time = get_time(GCodeProcessor::ETimeMode::Normal); print_statistics.estimated_normal_custom_gcode_print_times = get_custom_gcode_times(GCodeProcessor::ETimeMode::Normal, true); print_statistics.estimated_normal_moves_times = get_moves_time(GCodeProcessor::ETimeMode::Normal); + print_statistics.estimated_normal_roles_times = get_roles_time(GCodeProcessor::ETimeMode::Normal); if (m_time_processor.machines[static_cast(GCodeProcessor::ETimeMode::Stealth)].enabled) { print_statistics.estimated_silent_print_time = get_time(GCodeProcessor::ETimeMode::Stealth); print_statistics.estimated_silent_custom_gcode_print_times = get_custom_gcode_times(GCodeProcessor::ETimeMode::Stealth, true); print_statistics.estimated_silent_moves_times = get_moves_time(GCodeProcessor::ETimeMode::Stealth); + print_statistics.estimated_silent_roles_times = get_roles_time(GCodeProcessor::ETimeMode::Stealth); } else { print_statistics.estimated_silent_print_time = 0.0f; print_statistics.estimated_silent_custom_gcode_print_times.clear(); print_statistics.estimated_silent_moves_times.clear(); + print_statistics.estimated_silent_roles_times.clear(); } } @@ -447,6 +452,19 @@ std::vector> GCodeProcessor::get_mov return ret; } +std::vector> GCodeProcessor::get_roles_time(ETimeMode mode) const +{ + std::vector> ret; + if (mode < ETimeMode::Count) { + for (size_t i = 0; i < m_time_processor.machines[static_cast(mode)].roles_time.size(); ++i) { + float time = m_time_processor.machines[static_cast(mode)].roles_time[i]; + if (time > 0.0f) + ret.push_back({ static_cast(i), time }); + } + } + return ret; +} + void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line) { /* std::cout << line.raw() << std::endl; */ @@ -735,6 +753,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) TimeBlock block; block.move_type = type; + block.role = m_extrusion_role; block.distance = distance; // calculates block cruise feedrate diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 214ed3d91..d19d363f9 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -101,6 +101,7 @@ namespace Slic3r { }; EMoveType move_type{ EMoveType::Noop }; + ExtrusionRole role{ erNone }; float distance{ 0.0f }; // mm float acceleration{ 0.0f }; // mm/s^2 float max_entry_speed{ 0.0f }; // mm/s @@ -153,6 +154,7 @@ namespace Slic3r { CustomGCodeTime gcode_time; std::vector blocks; std::array(EMoveType::Count)> moves_time; + std::array(ExtrusionRole::erCount)> roles_time; void reset(); @@ -265,6 +267,7 @@ namespace Slic3r { std::vector>> get_custom_gcode_times(ETimeMode mode, bool include_remaining) const; std::vector> get_moves_time(ETimeMode mode) const; + std::vector> get_roles_time(ETimeMode mode) const; private: void process_gcode_line(const GCodeReader::GCodeLine& line); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 748411cd7..e2b7ab546 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -314,6 +314,8 @@ struct PrintStatistics std::vector>> estimated_silent_custom_gcode_print_times_str; std::vector> estimated_normal_moves_times; std::vector> estimated_silent_moves_times; + std::vector> estimated_normal_roles_times; + std::vector> estimated_silent_roles_times; #else std::string estimated_normal_print_time; std::string estimated_silent_print_time; @@ -366,6 +368,8 @@ struct PrintStatistics estimated_silent_custom_gcode_print_times.clear(); estimated_normal_moves_times.clear(); estimated_silent_moves_times.clear(); + estimated_normal_roles_times.clear(); + estimated_silent_roles_times.clear(); } #endif //ENABLE_GCODE_VIEWER }; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index db95c2b22..df29af67b 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1724,6 +1724,8 @@ void GCodeViewer::render_time_estimate() const using Times = std::pair; using TimesList = std::vector>; + using Headers = std::vector; + using ColumnOffsets = std::array; // helper structure containig the data needed to render the time items struct PartialTime @@ -1743,17 +1745,14 @@ void GCodeViewer::render_time_estimate() const using PartialTimes = std::vector; auto append_mode = [this, &imgui](float total_time, const PartialTimes& items, - const std::vector>& moves_time) { - auto append_partial_times = [this, &imgui](const PartialTimes& items) { - using Headers = std::vector; - const Headers headers = { - _u8L("Event"), - _u8L("Remaining"), - _u8L("Duration") - }; - using Offsets = std::array; + const Headers& partial_times_headers, + const std::vector>& moves_time, + const Headers& moves_headers, + const std::vector>& roles_time, + const Headers& roles_headers) { + auto append_partial_times = [this, &imgui](const PartialTimes& items, const Headers& headers) { auto calc_offsets = [this, &headers](const PartialTimes& items) { - Offsets ret = { ImGui::CalcTextSize(headers[0].c_str()).x, ImGui::CalcTextSize(headers[1].c_str()).x }; + ColumnOffsets ret = { ImGui::CalcTextSize(headers[0].c_str()).x, ImGui::CalcTextSize(headers[1].c_str()).x }; for (const PartialTime& item : items) { std::string label; switch (item.type) @@ -1772,7 +1771,7 @@ void GCodeViewer::render_time_estimate() const ret[1] += ret[0] + style.ItemSpacing.x; return ret; }; - auto append_color = [this, &imgui](const Color& color1, const Color& color2, Offsets& offsets, const Times& times) { + auto append_color = [this, &imgui](const Color& color1, const Color& color2, ColumnOffsets& offsets, const Times& times) { ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(_u8L("Color change")); ImGui::PopStyleColor(); @@ -1801,7 +1800,7 @@ void GCodeViewer::render_time_estimate() const if (items.empty()) return; - Offsets offsets = calc_offsets(items); + ColumnOffsets offsets = calc_offsets(items); ImGui::Spacing(); ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); @@ -1845,42 +1844,25 @@ void GCodeViewer::render_time_estimate() const } }; - auto append_move_times = [this, &imgui](float total_time, const std::vector>& moves_time) { - using Headers = std::vector; - const Headers headers = { - _u8L("Type"), - _u8L("Time"), - _u8L("Percentage") - }; - auto move_type_label = [](GCodeProcessor::EMoveType type) { - switch (type) - { - case GCodeProcessor::EMoveType::Noop: { return _u8L("Noop"); } - case GCodeProcessor::EMoveType::Retract: { return _u8L("Retraction"); } - case GCodeProcessor::EMoveType::Unretract: { return _u8L("Unretraction"); } - case GCodeProcessor::EMoveType::Tool_change: { return _u8L("Tool change"); } - case GCodeProcessor::EMoveType::Color_change: { return _u8L("Color change"); } - case GCodeProcessor::EMoveType::Pause_Print: { return _u8L("Pause print"); } - case GCodeProcessor::EMoveType::Custom_GCode: { return _u8L("Custom GCode"); } - case GCodeProcessor::EMoveType::Travel: { return _u8L("Travel"); } - case GCodeProcessor::EMoveType::Extrude: { return _u8L("Extrusion"); } - default: { return _u8L("Unknown"); } - } - }; - using Offsets = std::array; - auto calc_offsets = [this, &headers, move_type_label](const std::vector>& moves_time) { - Offsets ret = { ImGui::CalcTextSize(headers[0].c_str()).x, ImGui::CalcTextSize(headers[1].c_str()).x }; - for (const auto& [type, time] : moves_time) { - ret[0] = std::max(ret[0], ImGui::CalcTextSize(move_type_label(type).c_str()).x); - ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(time)).c_str()).x); - } - - const ImGuiStyle& style = ImGui::GetStyle(); - ret[0] += 2.0f * style.ItemSpacing.x; - ret[1] += ret[0] + style.ItemSpacing.x; - return ret; - }; + auto move_type_label = [](GCodeProcessor::EMoveType type) { + switch (type) + { + case GCodeProcessor::EMoveType::Noop: { return _u8L("Noop"); } + case GCodeProcessor::EMoveType::Retract: { return _u8L("Retraction"); } + case GCodeProcessor::EMoveType::Unretract: { return _u8L("Unretraction"); } + case GCodeProcessor::EMoveType::Tool_change: { return _u8L("Tool change"); } + case GCodeProcessor::EMoveType::Color_change: { return _u8L("Color change"); } + case GCodeProcessor::EMoveType::Pause_Print: { return _u8L("Pause print"); } + case GCodeProcessor::EMoveType::Custom_GCode: { return _u8L("Custom GCode"); } + case GCodeProcessor::EMoveType::Travel: { return _u8L("Travel"); } + case GCodeProcessor::EMoveType::Extrude: { return _u8L("Extrusion"); } + default: { return _u8L("Unknown"); } + } + }; + auto append_move_times = [this, &imgui, move_type_label](float total_time, + const std::vector>& moves_time, + const Headers& headers, const ColumnOffsets& offsets) { if (moves_time.empty()) return; @@ -1888,8 +1870,6 @@ void GCodeViewer::render_time_estimate() const if (!ImGui::CollapsingHeader(_u8L("Moves Time").c_str())) return; - Offsets offsets = calc_offsets(moves_time); - ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(headers[0]); ImGui::SameLine(offsets[0]); @@ -1899,7 +1879,10 @@ void GCodeViewer::render_time_estimate() const ImGui::PopStyleColor(); ImGui::Separator(); - for (const auto& [type, time] : moves_time) { + std::vector> sorted_moves_time(moves_time); + std::sort(sorted_moves_time.begin(), sorted_moves_time.end(), [](const auto& p1, const auto& p2) { return p2.second < p1.second; }); + + for (const auto& [type, time] : sorted_moves_time) { ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(move_type_label(type)); ImGui::PopStyleColor(); @@ -1912,13 +1895,72 @@ void GCodeViewer::render_time_estimate() const } }; + auto append_role_times = [this, &imgui](float total_time, + const std::vector>& roles_time, + const Headers& headers, const ColumnOffsets& offsets) { + + if (roles_time.empty()) + return; + + if (!ImGui::CollapsingHeader(_u8L("Features Time").c_str())) + return; + + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(headers[0]); + ImGui::SameLine(offsets[0]); + imgui.text(headers[1]); + ImGui::SameLine(offsets[1]); + imgui.text(headers[2]); + ImGui::PopStyleColor(); + ImGui::Separator(); + + std::vector> sorted_roles_time(roles_time); + std::sort(sorted_roles_time.begin(), sorted_roles_time.end(), [](const auto& p1, const auto& p2) { return p2.second < p1.second; }); + + for (const auto& [role, time] : sorted_roles_time) { + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_u8L(ExtrusionEntity::role_to_string(role))); + ImGui::PopStyleColor(); + ImGui::SameLine(offsets[0]); + imgui.text(short_time(get_time_dhms(time))); + ImGui::SameLine(offsets[1]); + char buf[64]; + ::sprintf(buf, "%.2f%%", 100.0f * time / total_time); + ImGui::TextUnformatted(buf); + } + }; + + auto calc_common_offsets = [move_type_label]( + const std::vector>& moves_time, const Headers& moves_headers, + const std::vector>& roles_time, const Headers& roles_headers) { + ColumnOffsets ret = { std::max(ImGui::CalcTextSize(moves_headers[0].c_str()).x, ImGui::CalcTextSize(roles_headers[0].c_str()).x), + std::max(ImGui::CalcTextSize(moves_headers[1].c_str()).x, ImGui::CalcTextSize(roles_headers[1].c_str()).x) }; + + for (const auto& [type, time] : moves_time) { + ret[0] = std::max(ret[0], ImGui::CalcTextSize(move_type_label(type).c_str()).x); + ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(time)).c_str()).x); + } + + for (const auto& [role, time] : roles_time) { + ret[0] = std::max(ret[0], ImGui::CalcTextSize(_u8L(ExtrusionEntity::role_to_string(role)).c_str()).x); + ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(time)).c_str()).x); + } + + const ImGuiStyle& style = ImGui::GetStyle(); + ret[0] += 2.0f * style.ItemSpacing.x; + ret[1] += ret[0] + style.ItemSpacing.x; + return ret; + }; + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(_u8L("Time") + ":"); ImGui::PopStyleColor(); ImGui::SameLine(); imgui.text(short_time(get_time_dhms(total_time))); - append_partial_times(items); - append_move_times(total_time, moves_time); + append_partial_times(items, partial_times_headers); + ColumnOffsets common_offsets = calc_common_offsets(moves_time, moves_headers, roles_time, roles_headers); + append_move_times(total_time, moves_time, moves_headers, common_offsets); + append_role_times(total_time, roles_time, roles_headers, common_offsets); }; auto generate_partial_times = [this](const TimesList& times) { @@ -1966,6 +2008,22 @@ void GCodeViewer::render_time_estimate() const return items; }; + const Headers partial_times_headers = { + _u8L("Event"), + _u8L("Remaining"), + _u8L("Duration") + }; + const Headers moves_headers = { + _u8L("Type"), + _u8L("Time"), + _u8L("Percentage") + }; + const Headers roles_headers = { + _u8L("Feature"), + _u8L("Time"), + _u8L("Percentage") + }; + Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); imgui.set_next_window_pos(static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(-1.0f, 0.5f * static_cast(cnv_size.get_height()))); @@ -1980,13 +2038,19 @@ void GCodeViewer::render_time_estimate() const ImGui::BeginTabBar("mode_tabs"); if (ps.estimated_normal_print_time > 0.0f) { if (ImGui::BeginTabItem(_u8L("Normal").c_str())) { - append_mode(ps.estimated_normal_print_time, generate_partial_times(ps.estimated_normal_custom_gcode_print_times), ps.estimated_normal_moves_times); + append_mode(ps.estimated_normal_print_time, + generate_partial_times(ps.estimated_normal_custom_gcode_print_times), partial_times_headers, + ps.estimated_normal_moves_times, moves_headers, + ps.estimated_normal_roles_times, roles_headers); ImGui::EndTabItem(); } } if (ps.estimated_silent_print_time > 0.0f) { if (ImGui::BeginTabItem(_u8L("Stealth").c_str())) { - append_mode(ps.estimated_silent_print_time, generate_partial_times(ps.estimated_silent_custom_gcode_print_times), ps.estimated_silent_moves_times); + append_mode(ps.estimated_silent_print_time, + generate_partial_times(ps.estimated_silent_custom_gcode_print_times), partial_times_headers, + ps.estimated_silent_moves_times, moves_headers, + ps.estimated_silent_roles_times, roles_headers); ImGui::EndTabItem(); } }