diff --git a/resources/localization/uk/Slic3rPE.mo b/resources/localization/uk/Slic3rPE.mo index 56af728d6..08bf555b5 100644 Binary files a/resources/localization/uk/Slic3rPE.mo and b/resources/localization/uk/Slic3rPE.mo differ diff --git a/resources/localization/uk/Slic3rPE_uk.po b/resources/localization/uk/Slic3rPE_uk.po index 9db2b919a..7880453bb 100644 --- a/resources/localization/uk/Slic3rPE_uk.po +++ b/resources/localization/uk/Slic3rPE_uk.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-01-17 13:39+0100\n" -"PO-Revision-Date: 2019-01-21 11:25+0100\n" +"PO-Revision-Date: 2019-02-19 14:42+0100\n" "Last-Translator: Oleksandra Iushchenko \n" "Language-Team: \n" "Language: uk\n" @@ -624,48 +624,48 @@ msgstr "" #: src/slic3r/GUI/GLGizmo.cpp:2207 msgid "Left mouse click - add point" -msgstr "" +msgstr "Ліва кнопка миші - додати точку" #: src/slic3r/GUI/GLGizmo.cpp:2208 msgid "Right mouse click - remove point" -msgstr "" +msgstr "Права кнопка миші - видалити точку" #: src/slic3r/GUI/GLGizmo.cpp:2211 msgid "Generate points automatically" -msgstr "" +msgstr "Генерувати точки автоматично" #: src/slic3r/GUI/GLGizmo.cpp:2212 msgid "Remove all points" -msgstr "" +msgstr "Видалити всі точки" #: src/slic3r/GUI/GLGizmo.cpp:2245 msgid "SLA Support Points" -msgstr "" +msgstr "Точки SLA підтримки" #: src/slic3r/GUI/GLGizmo.cpp:2268 src/slic3r/GUI/GLGizmo.cpp:2468 msgid "Rotate lower part upwards" -msgstr "" +msgstr "Повернути нижню частину вгору" #: src/slic3r/GUI/GLGizmo.cpp:2269 src/slic3r/GUI/GLGizmo.cpp:2470 msgid "Perform cut" -msgstr "" +msgstr "Виконати розріз" #: src/slic3r/GUI/GLGizmo.cpp:2276 msgid "Cut object:" -msgstr "" +msgstr "Розрізати об'єкт:" #: src/slic3r/GUI/GLGizmo.cpp:2356 src/slic3r/GUI/GLGizmo.cpp:2461 #: src/libslic3r/PrintConfig.cpp:3016 msgid "Cut" -msgstr "" +msgstr "Розрізати" #: src/slic3r/GUI/GLGizmo.cpp:2466 msgid "Keep upper part" -msgstr "" +msgstr "Залишити верхню частину" #: src/slic3r/GUI/GLGizmo.cpp:2467 msgid "Keep lower part" -msgstr "" +msgstr "Залишити нижню частину" #: src/slic3r/GUI/GUI.cpp:242 msgid "Notice" @@ -5636,7 +5636,7 @@ msgstr "" #: src/libslic3r/PrintConfig.cpp:3017 msgid "Cut model at the given Z." -msgstr "" +msgstr "Розрізати модель за заданим Z." #: src/libslic3r/PrintConfig.cpp:3022 msgid "Dont arrange" diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6416a709a..d47cdf99f 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -280,7 +280,7 @@ bool Print::is_step_done(PrintObjectStep step) const return false; tbb::mutex::scoped_lock lock(this->state_mutex()); for (const PrintObject *object : m_objects) - if (! object->m_state.is_done_unguarded(step)) + if (! object->is_step_done_unguarded(step)) return false; return true; } @@ -549,10 +549,14 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con assert(! it->second); // not consumed yet it->second = true; ModelVolume *model_volume_dst = const_cast(it->first); - assert(model_volume_dst->type() == model_volume_src->type()); + // For support modifiers, the type may have been switched from blocker to enforcer and vice versa. + assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) || model_volume_dst->type() == model_volume_src->type()); model_object_dst.volumes.emplace_back(model_volume_dst); - if (model_volume_dst->is_support_modifier()) - model_volume_dst->set_transformation(model_volume_src->get_transformation()); + if (model_volume_dst->is_support_modifier()) { + // For support modifiers, the type may have been switched from blocker to enforcer and vice versa. + model_volume_dst->set_type(model_volume_src->type()); + model_volume_dst->set_transformation(model_volume_src->get_transformation()); + } assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix())); } else { // The volume was not found in the old list. Create a new copy. diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index f67ec4b72..e70edd20d 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -62,6 +62,10 @@ public: return state; } + bool is_started(StepType step, tbb::mutex &mtx) const { + return this->state_with_timestamp(step, mtx).state == STARTED; + } + bool is_done(StepType step, tbb::mutex &mtx) const { return this->state_with_timestamp(step, mtx).state == DONE; } @@ -70,6 +74,10 @@ public: return m_state[step]; } + bool is_started_unguarded(StepType step) const { + return this->state_with_timestamp_unguarded(step).state == STARTED; + } + bool is_done_unguarded(StepType step) const { return this->state_with_timestamp_unguarded(step).state == DONE; } @@ -235,7 +243,24 @@ public: virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; const Model& model() const { return m_model; } + struct TaskParams { + TaskParams() : single_model_object(0), single_model_instance_only(false), to_object_step(-1), to_print_step(-1) {} + // If non-empty, limit the processing to this ModelObject. + ModelID single_model_object; + // If set, only process single_model_object. Otherwise process everything, but single_model_object first. + bool single_model_instance_only; + // If non-negative, stop processing at the successive object step. + int to_object_step; + // If non-negative, stop processing at the successive print step. + int to_print_step; + }; + // After calling the apply() function, call set_task() to limit the task to be processed by process(). + virtual void set_task(const TaskParams ¶ms) {} + // Perform the calculation. This is the only method that is to be called at a worker thread. virtual void process() = 0; + // Clean up after process() finished, either with success, error or if canceled. + // The adjustments on the Print / PrintObject data due to set_task() are to be reverted here. + virtual void finalize() {} struct SlicingStatus { SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {} @@ -350,6 +375,9 @@ protected: bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_callback()); } + bool is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); } + bool is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); } + private: PrintState m_state; }; @@ -383,6 +411,9 @@ protected: bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); } + bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); } + bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); } + protected: // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f25087cbe..213437612 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -51,7 +51,7 @@ const std::array OBJ_STEP_LABELS = L("Slicing model"), // slaposObjectSlice, L("Generating support points"), // slaposSupportPoints, L("Generating support tree"), // slaposSupportTree, - L("Generating base pool"), // slaposBasePool, + L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, L("Slicing supports") // slaposIndexSlices, }; @@ -402,6 +402,80 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf return static_cast(apply_status); } +// After calling the apply() function, set_task() may be called to limit the task to be processed by process(). +void SLAPrint::set_task(const TaskParams ¶ms) +{ + // Grab the lock for the Print / PrintObject milestones. + tbb::mutex::scoped_lock lock(this->state_mutex()); + + int n_object_steps = int(params.to_object_step) + 1; + if (n_object_steps == 0) + n_object_steps = (int)slaposCount; + + if (params.single_model_object.valid()) { + SLAPrintObject *print_object = nullptr; + size_t idx_print_object = 0; + for (; idx_print_object < m_objects.size(); ++idx_print_object) + if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) { + print_object = m_objects[idx_print_object]; + break; + } + assert(print_object != nullptr); + bool shall_cancel = false; + for (int istep = 0; istep < n_object_steps; ++istep) + if (! print_object->m_stepmask[istep]) { + shall_cancel = true; + break; + } + bool running = false; + if (!shall_cancel) { + for (int istep = 0; istep < n_object_steps; ++ istep) + if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { + running = true; + break; + } + } + if (!running) + this->cancel_callback(); + + // Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway. + if (params.single_model_instance_only) { + // Suppress all the steps of other instances. + for (SLAPrintObject *po : m_objects) + for (int istep = 0; istep < (int)slaposCount; ++istep) + po->m_stepmask[istep] = false; + } + else if (!running) { + // Swap the print objects, so that the selected print_object is first in the row. + // At this point the background processing must be stopped, so it is safe to shuffle print objects. + if (idx_print_object != 0) + std::swap(m_objects.front(), m_objects[idx_print_object]); + } + for (int istep = 0; istep < n_object_steps; ++ istep) + print_object->m_stepmask[istep] = true; + for (int istep = n_object_steps; istep < (int)slaposCount; ++istep) + print_object->m_stepmask[istep] = false; + } + + if (params.to_object_step != -1 || params.to_print_step != -1) { + // Limit the print steps. + size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1; + for (; istep < m_stepmask.size(); ++ istep) + m_stepmask[istep] = false; + } +} + +// Clean up after process() finished, either with success, error or if canceled. +// The adjustments on the SLAPrint / SLAPrintObject data due to set_task() are to be reverted here. +void SLAPrint::finalize() +{ + for (SLAPrintObject *po : m_objects) + for (int istep = 0; istep < (int)slaposCount; ++ istep) + po->m_stepmask[istep] = true; + for (int istep = 0; istep < (int)slapsCount; ++ istep) + m_stepmask[istep] = true; +} + namespace { // Compile the argument for support creation from the static print config. sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { @@ -1035,7 +1109,7 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const return false; tbb::mutex::scoped_lock lock(this->state_mutex()); for (const SLAPrintObject *object : m_objects) - if (! object->m_state.is_done_unguarded(step)) + if (! object->is_step_done_unguarded(step)) return false; return true; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9aaba6a47..68a0d34aa 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -139,6 +139,10 @@ protected: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); + // Which steps have to be performed. Implicitly: all + // to be accessible from SLAPrint + std::vector m_stepmask; + private: // Object specific configuration, pulled from the configuration layer. SLAPrintObjectConfig m_config; @@ -146,9 +150,6 @@ private: Transform3d m_trafo = Transform3d::Identity(); std::vector m_instances; - // Which steps have to be performed. Implicitly: all - std::vector m_stepmask; - // Individual 2d slice polygons from lower z to higher z levels std::vector m_model_slices; @@ -194,7 +195,9 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + void set_task(const TaskParams ¶ms) override; void process() override; + void finalize() override; // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; // Returns true if the last step was finished with success. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 463be8397..7c8164f6b 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -196,6 +196,7 @@ void BackgroundSlicingProcess::thread_proc() } catch (...) { error = "Unknown C++ exception."; } + m_print->finalize(); lck.lock(); m_state = m_print->canceled() ? STATE_CANCELED : STATE_FINISHED; if (m_print->cancel_status() != Print::CANCELED_INTERNAL) { @@ -362,6 +363,12 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn return invalidated; } +void BackgroundSlicingProcess::set_task(const PrintBase::TaskParams ¶ms) +{ + assert(m_print != nullptr); + m_print->set_task(params); +} + // Set the output path of the G-code. void BackgroundSlicingProcess::schedule_export(const std::string &path) { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 5911c8a02..a2299e7bf 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -78,6 +78,9 @@ public: // Apply config over the print. Returns false, if the new config values caused any of the already // processed steps to be invalidated, therefore the task will need to be restarted. Print::ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); + // After calling the apply() function, set_task() may be called to limit the task to be processed by process(). + // This is useful for calculating SLA supports for a single object only. + void set_task(const PrintBase::TaskParams ¶ms); // After calling apply, the empty() call will report whether there is anything to slice. bool empty() const; // Validate the print. Returns an empty string if valid, returns an error message if invalid. @@ -94,6 +97,7 @@ public: void reset_export(); // Once the G-code export is scheduled, the apply() methods will do nothing. bool is_export_scheduled() const { return ! m_export_path.empty(); } + bool is_upload_scheduled() const { return ! m_upload_job.empty(); } enum State { // m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet). diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 47128ba67..ad949cbf5 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2039,6 +2039,13 @@ unsigned int Plater::priv::update_background_process(bool force_validation) wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); } + //FIXME update "Slice Now / Schedule background process" + //background_process.is_export_scheduled() - byl zavolan "Export G-code", background processing ma jmeno export souboru + //background_process.is_upload_scheduled() - byl zavolan "Send to OctoPrint", jeste nebylo doslajsovano (pak se preda upload fronte a background process zapomene) + //background_process.empty() - prazdna plocha + // pokud (invalidated != Print::APPLY_STATUS_UNCHANGED) a ! background_process.empty() -> je neco ke slajsovani (povol tlacitko) + // pokud (return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0 -> doslo k chybe (gray out "Slice now") + return return_state; } @@ -3016,6 +3023,32 @@ void Plater::reslice() this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART); } +void Plater::reslice_SLA_supports(const ModelObject &object) +{ + //FIXME Don't reslice if export of G-code or sending to OctoPrint is running. + // bitmask of UpdateBackgroundProcessReturnState + unsigned int state = this->p->update_background_process(true); + if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) + this->p->view3D->reload_scene(false); + + if (this->p->background_process.empty() || (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)) + // Nothing to do on empty input or invalid configuration. + return; + + // Limit calculation to the single object only. + PrintBase::TaskParams task; + task.single_model_object = object.id(); + // If the background processing is not enabled, calculate supports just for the single instance. + // Otherwise calculate everything, but start with the provided object. + if (!this->p->background_processing_enabled()) { + task.single_model_instance_only = true; + task.to_object_step = slaposBasePool; + } + this->p->background_process.set_task(task); + // and let the background processing start. + this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART); +} + void Plater::send_gcode() { if (p->model.objects.empty()) { return; } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index c8c17bed8..4d489c82a 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -22,6 +22,7 @@ class wxString; namespace Slic3r { class Model; +class ModelObject; class Print; class SLAPrint; @@ -148,6 +149,7 @@ public: void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); void reslice(); + void reslice_SLA_supports(const ModelObject &object); void changed_object(int obj_idx); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void send_gcode(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1c67e542a..dc82d1a39 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -669,6 +669,7 @@ void Tab::load_config(const DynamicPrintConfig& config) bool modified = 0; for(auto opt_key : m_config->diff(config)) { m_config->set_key_value(opt_key, config.option(opt_key)->clone()); + m_dirty_options.emplace(opt_key); modified = 1; } if (modified) { @@ -751,17 +752,7 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { - wxCommandEvent event(EVT_TAB_VALUE_CHANGED); - event.SetEventObject(this); - event.SetString(opt_key); - if (opt_key == "extruders_count") - { - int val = boost::any_cast(value); - event.SetInt(val); - } - - wxPostEvent(this, event); - + m_dirty_options.erase(opt_key); ConfigOptionsGroup* og_freq_chng_params = wxGetApp().sidebar().og_freq_chng_params(supports_printer_technology(ptFFF)); if (opt_key == "fill_density" || opt_key == "supports_enable" || opt_key == "pad_enable") @@ -788,6 +779,21 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) update_wiping_button_visibility(); update(); + + // Post event to the Plater after updating of the all dirty options + // It helps to avoid needless schedule_background_processing + if (update_completed()) { + wxCommandEvent event(EVT_TAB_VALUE_CHANGED); + event.SetEventObject(this); + event.SetString(opt_key); + if (opt_key == "extruders_count") + { + const int val = boost::any_cast(value); + event.SetInt(val); + } + + wxPostEvent(this, event); + } } // Show/hide the 'purging volumes' button @@ -1163,8 +1169,8 @@ void TabPrint::update() // KillFocus() for the wxSpinCtrl use CallAfter function. So, // to except the duplicate call of the update() after dialog->ShowModal(), // let check if this process is already started. - if (is_msg_dlg_already_exist) - return; +// if (is_msg_dlg_already_exist) // ! It looks like a fixed problem after start to using of a m_dirty_options +// return; // ! TODO Let delete this part of code after a common aplication testing Freeze(); @@ -1181,7 +1187,7 @@ void TabPrint::update() "- no ensure_vertical_shell_thickness\n" "\nShall I adjust those settings in order to enable Spiral Vase?")); auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); - is_msg_dlg_already_exist = true; +// is_msg_dlg_already_exist = true; DynamicPrintConfig new_conf = *m_config; if (dialog->ShowModal() == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); @@ -1197,7 +1203,7 @@ void TabPrint::update() } load_config(new_conf); on_value_change("fill_density", fill_density); - is_msg_dlg_already_exist = false; +// is_msg_dlg_already_exist = false; } if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") && diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index c9802d9cf..135420edb 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -204,6 +204,7 @@ protected: void set_type(); int m_em_unit; + std::set m_dirty_options = {}; public: PresetBundle* m_preset_bundle; @@ -283,6 +284,7 @@ protected: void update_frequently_changed_parameters(); void fill_icon_descriptions(); void set_tooltips_text(); + bool update_completed() const { return m_dirty_options.empty(); } }; class TabPrint : public Tab