From c04be58648b663eeb5e1f10572b0c19d94ec9815 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 12 Feb 2019 16:34:42 +0100 Subject: [PATCH] Implemented estimated printing time for the SLA printing --- src/libslic3r/Print.cpp | 4 +- src/libslic3r/SLAPrint.cpp | 80 ++++++++++++++++++++++++++++++++++++++ src/libslic3r/SLAPrint.hpp | 30 ++++++++++++++ src/libslic3r/Utils.hpp | 63 ++++++++++++++++++++++++++++++ src/slic3r/GUI/Plater.cpp | 21 ++++++++++ 5 files changed, 196 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6416a709a..3e78c9a85 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1863,7 +1863,7 @@ std::string Print::output_filename() const DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); return this->PrintBase::output_filename(m_config.output_filename_format.value, "gcode", &config); } - +/* // Shorten the dhms time by removing the seconds, rounding the dhm to full minutes // and removing spaces. static std::string short_time(const std::string &time) @@ -1903,7 +1903,7 @@ static std::string short_time(const std::string &time) ::sprintf(buffer, "%ds", seconds); return buffer; } - +*/ DynamicConfig PrintStatistics::config() const { DynamicConfig config; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 142428f1d..b848e2698 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -966,6 +966,9 @@ void SLAPrint::process() st += unsigned(PRINT_STEP_LEVELS[currentstep] * pstd); } + // Fill statistics + fill_statistics(); + // If everything vent well report_status(*this, 100, L("Slicing done")); } @@ -1027,6 +1030,46 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt return invalidated; } +void SLAPrint::fill_statistics() +{ + int max_layers_cnt = 0; + for (SLAPrintObject * po : m_objects) { + if (max_layers_cnt < po->get_slice_index().size()) + max_layers_cnt = po->get_slice_index().size(); + } + if (max_layers_cnt == 0) + return; + + float init_exp_time = m_material_config.initial_exposure_time.getFloat();//35; + float exp_time = m_material_config.exposure_time.getFloat();//8; + + // TODO : fade_layers_cnt should be filled in the future + // This variable will be a part of the print(material) preset + const int fade_layers_cnt = 10; // [3;20] + + // TODO : tilt_delay_before_time & tilt_delay_after_time should be filled in the future + // These values are received from the printer after a printing start + const float tilt_delay_before_time = 0.0; + const float tilt_delay_after_time = 0.0; + if (tilt_delay_before_time + tilt_delay_after_time > 0.0) + { + init_exp_time += tilt_delay_before_time + tilt_delay_after_time; + exp_time += tilt_delay_before_time + tilt_delay_after_time; + } + + float estim_time = init_exp_time * 3 + exp_time * (max_layers_cnt - 3 - fade_layers_cnt); + + const float delta_time = (init_exp_time - exp_time) / (fade_layers_cnt+1); + double fade_layer_time = init_exp_time; + while (fade_layer_time > exp_time) + { + fade_layer_time -= delta_time; + estim_time += fade_layer_time; + } + + m_print_statistics.estimated_print_time = get_time_dhms(estim_time); +} + // Returns true if an object step is done on all objects and there's at least one object. bool SLAPrint::is_step_done(SLAPrintObjectStep step) const { @@ -1257,4 +1300,41 @@ std::vector<Vec3d> SLAPrintObject::transformed_support_points() const return ret; } +DynamicConfig SLAPrintStatistics::config() const +{ + DynamicConfig config; + const std::string print_time = Slic3r::short_time(this->estimated_print_time); + config.set_key_value("print_time", new ConfigOptionString(print_time)); + config.set_key_value("used_material", new ConfigOptionFloat(this->total_used_material/* / 1000.*/)); + config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost)); + config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight)); + return config; +} + +DynamicConfig SLAPrintStatistics::placeholders() +{ + DynamicConfig config; + for (const std::string &key : { + "print_time", "used_material", "total_cost", "total_weight" }) + config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}")); + return config; +} + +std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const +{ + std::string final_path; + try { + boost::filesystem::path path(path_in); + DynamicConfig cfg = this->config(); + PlaceholderParser pp; + std::string new_stem = pp.process(path.stem().string(), 0, &cfg); + final_path = (path.parent_path() / (new_stem + path.extension().string())).string(); + } + catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Failed to apply the print statistics to the export file name: " << ex.what(); + final_path = path_in; + } + return final_path; +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 21503c6f6..0e12fff63 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -171,6 +171,29 @@ using PrintObjects = std::vector<SLAPrintObject*>; class TriangleMesh; +struct SLAPrintStatistics +{ + SLAPrintStatistics() { clear(); } + std::string estimated_print_time; + double total_used_material; + double total_cost; + double total_weight; + + // Config with the filled in print statistics. + DynamicConfig config() const; + // Config with the statistics keys populated with placeholder strings. + static DynamicConfig placeholders(); + // Replace the print statistics placeholders in the path. + std::string finalize_output_path(const std::string &path_in) const; + + void clear() { + estimated_print_time.clear(); + total_used_material = 0.; + total_cost = 0.; + total_weight = 0.; + } +}; + /** * @brief This class is the high level FSM for the SLA printing process. * @@ -208,6 +231,8 @@ public: std::string output_filename() const override { return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "zip"); } + const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } + private: using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; using SLAPrinterPtr = std::unique_ptr<SLAPrinter>; @@ -215,6 +240,8 @@ private: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); + void fill_statistics(); + SLAPrintConfig m_print_config; SLAPrinterConfig m_printer_config; SLAMaterialConfig m_material_config; @@ -246,6 +273,9 @@ private: // The printer itself SLAPrinterPtr m_printer; + // Estimated print time, material consumed. + SLAPrintStatistics m_print_statistics; + friend SLAPrintObject; }; diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 046745e6f..c13df4546 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -206,6 +206,69 @@ public: void reset() { closure = Closure(); } }; +// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes +// and removing spaces. +static std::string short_time(const std::string &time) +{ + // Parse the dhms time format. + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + if (time.find('d') != std::string::npos) + ::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds); + else if (time.find('h') != std::string::npos) + ::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds); + else if (time.find('m') != std::string::npos) + ::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds); + else if (time.find('s') != std::string::npos) + ::sscanf(time.c_str(), "%ds", &seconds); + // Round to full minutes. + if (days + hours + minutes > 0 && seconds >= 30) { + if (++minutes == 60) { + minutes = 0; + if (++hours == 24) { + hours = 0; + ++days; + } + } + } + // Format the dhm time. + char buffer[64]; + if (days > 0) + ::sprintf(buffer, "%dd%dh%dm", days, hours, minutes); + else if (hours > 0) + ::sprintf(buffer, "%dh%dm", hours, minutes); + else if (minutes > 0) + ::sprintf(buffer, "%dm", minutes); + else + ::sprintf(buffer, "%ds", seconds); + return buffer; +} + +// Returns the given time is seconds in format DDd HHh MMm SSs +static std::string get_time_dhms(float time_in_secs) +{ + int days = (int)(time_in_secs / 86400.0f); + time_in_secs -= (float)days * 86400.0f; + int hours = (int)(time_in_secs / 3600.0f); + time_in_secs -= (float)hours * 3600.0f; + int minutes = (int)(time_in_secs / 60.0f); + time_in_secs -= (float)minutes * 60.0f; + + char buffer[64]; + if (days > 0) + ::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs); + else if (hours > 0) + ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs); + else if (minutes > 0) + ::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs); + else + ::sprintf(buffer, "%ds", (int)time_in_secs); + + return buffer; +} + } // namespace Slic3r #if WIN32 diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 774e61024..18a923d45 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -153,6 +153,7 @@ enum SlisedInfoIdx siFilament_m, siFilament_mm3, siFilament_g, + siMateril_unit, siCost, siEstimatedTime, siWTNumbetOfToolchanges, @@ -193,6 +194,7 @@ SlicedInfo::SlicedInfo(wxWindow *parent) : init_info_label(_(L("Used Filament (m)"))); init_info_label(_(L("Used Filament (mm³)"))); init_info_label(_(L("Used Filament (g)"))); + init_info_label(_(L("Used Material (unit)"))); init_info_label(_(L("Cost"))); init_info_label(_(L("Estimated printing time"))); init_info_label(_(L("Number of tool changes"))); @@ -817,6 +819,21 @@ void Sidebar::show_sliced_info_sizer(const bool show) p->sliced_info->Show(show); if (show) { + if (p->plater->printer_technology() == ptSLA) + { + const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics(); + p->sliced_info->SetTextAndShow(siMateril_unit, wxString::Format("%.2f", ps.total_used_material)); + p->sliced_info->SetTextAndShow(siCost, wxString::Format("%.2f", ps.total_cost)); + p->sliced_info->SetTextAndShow(siEstimatedTime, ps.estimated_print_time, _(L("Estimated printing time")) + " :"); + + // Hide non-SLA sliced info parameters + p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); + p->sliced_info->SetTextAndShow(siFilament_mm3, "N/A"); + p->sliced_info->SetTextAndShow(siFilament_g, "N/A"); + p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, "N/A"); + } + else + { const PrintStatistics& ps = p->plater->fff_print().print_statistics(); const bool is_wipe_tower = ps.total_wipe_tower_filament > 0; @@ -864,6 +881,10 @@ void Sidebar::show_sliced_info_sizer(const bool show) // if there is a wipe tower, insert number of toolchanges info into the array: p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->fff_print().wipe_tower_data().number_of_toolchanges) : "N/A"); + + // Hide non-FFF sliced info parameters + p->sliced_info->SetTextAndShow(siMateril_unit, "N/A"); + } } Layout();