diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0acbdd123..c4d0c1bd9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1238,7 +1238,7 @@ void GCode::process_layer( const size_t single_object_idx) { assert(! layers.empty()); - assert(! layer_tools.extruders.empty()); +// assert(! layer_tools.extruders.empty()); // Either printing all copies of all objects, or just a single copy of a single object. assert(single_object_idx == size_t(-1) || layers.size() == 1); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index c8c1991d6..bc9935086 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -19,33 +19,28 @@ namespace Slic3r { - unsigned int Model::s_auto_extruder_id = 1; +unsigned int Model::s_auto_extruder_id = 1; ModelID ModelBase::s_last_id = 0; -Model::Model(const Model &other) +Model::Model(const Model &rhs) { + *this = rhs; +} + +Model& Model::operator=(const Model &rhs) +{ + m_id = rhs.m_id; // copy materials - for (const auto &m : other.materials) + for (const auto &m : rhs.materials) this->add_material(m.first, *m.second); // copy objects - this->objects.reserve(other.objects.size()); - for (const ModelObject *o : other.objects) + this->objects.reserve(rhs.objects.size()); + for (const ModelObject *o : rhs.objects) this->add_object(*o, true); -} - -Model& Model::operator=(Model other) -{ - this->swap(other); return *this; } -void Model::swap(Model &other) -{ - std::swap(this->materials, other.materials); - std::swap(this->objects, other.objects); -} - Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances) { Model model; @@ -499,33 +494,11 @@ ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volum for (ModelVolume *model_volume : other.volumes) this->add_volume(*model_volume); } - this->instances.reserve(other.instances.size()); for (const ModelInstance *model_instance : other.instances) this->add_instance(*model_instance); } -ModelObject& ModelObject::operator=(ModelObject other) -{ - this->swap(other); - return *this; -} - -void ModelObject::swap(ModelObject &other) -{ - std::swap(this->m_id, other.m_id); - std::swap(this->input_file, other.input_file); - std::swap(this->instances, other.instances); - std::swap(this->volumes, other.volumes); - std::swap(this->config, other.config); - std::swap(this->layer_height_ranges, other.layer_height_ranges); - std::swap(this->layer_height_profile, other.layer_height_profile); - std::swap(this->layer_height_profile_valid, other.layer_height_profile_valid); - std::swap(this->origin_translation, other.origin_translation); - std::swap(m_bounding_box, other.m_bounding_box); - std::swap(m_bounding_box_valid, other.m_bounding_box_valid); -} - ModelObject::~ModelObject() { this->clear_volumes(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ece52c3dc..4ca7e140c 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -37,6 +37,8 @@ typedef size_t ModelID; // Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID // to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject). +// Achtung! The s_last_id counter is not thread safe, so it is expected, that the ModelBase derived instances +// are only instantiated from the main thread. class ModelBase { public: @@ -168,8 +170,6 @@ protected: private: ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true); - ModelObject& operator= (ModelObject other); - void swap(ModelObject &other); ~ModelObject(); // Parent object, owning this ModelObject. @@ -352,9 +352,8 @@ public: ModelObjectPtrs objects; Model() {} - Model(const Model &other); - Model& operator= (Model other); - void swap(Model &other); + Model(const Model &rhs); + Model& operator=(const Model &rhs); ~Model() { this->clear_objects(); this->clear_materials(); } // XXX: use fs::path ? diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index aa6c922aa..7c4a4c039 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -136,7 +136,7 @@ bool BackgroundSlicingProcess::stop() this->m_output_path.clear(); return false; } - assert(this->running()); +// assert(this->running()); if (m_state == STATE_STARTED || m_state == STATE_RUNNING) { m_print->cancel(); // Wait until the background processing stops by being canceled. @@ -160,4 +160,13 @@ bool BackgroundSlicingProcess::apply_config(const DynamicPrintConfig &config) return invalidated; } +// 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. +bool BackgroundSlicingProcess::apply(const Model &model, const DynamicPrintConfig &config) +{ + this->stop(); + bool invalidated = m_print->apply(model, config); + return invalidated; +} + }; // namespace Slic3r diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index cc7a6db30..758acd682 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -10,6 +10,7 @@ namespace Slic3r { class DynamicPrintConfig; class GCodePreviewData; +class Model; class Print; // Support for the GUI background processing (Slicing and G-code generation). @@ -42,6 +43,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. bool apply_config(const DynamicPrintConfig &config); + // 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. + bool apply(const Model &model, const DynamicPrintConfig &config); 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 37b1aa400..b62194b3d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1199,8 +1199,8 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode } } - print.auto_assign_extruders(object); - print.add_model_object(object); + // print.auto_assign_extruders(object); + // print.add_model_object(object); } // if user turned autocentering off, automatic arranging would disappoint them @@ -1520,9 +1520,9 @@ void Plater::priv::mirror(const Axis &axis) // $self->stop_background_process; // TODO #if ENABLE_EXTENDED_SELECTION - print.add_model_object(model_object, obj_idx); +// print.add_model_object(model_object, obj_idx); #else - print.add_model_object(model_object, *obj_idx); +// print.add_model_object(model_object, *obj_idx); #endif // ENABLE_EXTENDED_SELECTION selection_changed(); update(); @@ -1560,7 +1560,7 @@ void Plater::priv::async_apply_config() { // Apply new config to the possibly running background task. bool was_running = this->background_process.running(); - bool invalidated = this->background_process.apply_config(wxGetApp().preset_bundle->full_config()); + bool invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config()); // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D)) this->canvas3D->Refresh(); @@ -1580,9 +1580,11 @@ void Plater::priv::async_apply_config() this->preview->reload_print(); // We also need to reload 3D scene because of the wipe tower preview box if (this->config->opt_bool("wipe_tower")) { +#if !ENABLE_EXTENDED_SELECTION std::vector selections = this->collect_selections(); Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections); Slic3r::_3DScene::reload_scene(this->canvas3D, 1); +#endif /* !ENABLE_EXTENDED_SELECTION */ } } } @@ -1590,12 +1592,26 @@ void Plater::priv::async_apply_config() void Plater::priv::start_background_process() { - // TODO + // return if ! @{$self->{objects}} || $self->{background_slicing_process}->running; + // Don't start process thread if config is not valid. + std::string err = wxGetApp().preset_bundle->full_config().validate(); + if (err.empty()) + err = this->q->print().validate(); + if (! err.empty()) { + // $self->statusbar->SetStatusText(err); + return; + } + // Copy the names of active presets into the placeholder parser. + wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser()); + // Start the background process. + this->background_process.start(); } void Plater::priv::stop_background_process() { - // TODO + this->background_process.stop(); + if (this->preview != nullptr) + this->preview->reload_print(); } void Plater::priv::reload_from_disk() @@ -1610,7 +1626,33 @@ void Plater::priv::export_object_stl() void Plater::priv::fix_through_netfabb() { - // TODO +/* + my ($self) = @_; + my ($obj_idx, $object) = $self->selected_object; + return if !defined $obj_idx; + my $model_object = $self->{model}->objects->[$obj_idx]; + my $model_fixed = Slic3r::Model->new; + Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed); + + my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects}); + return if !@new_obj_idx; + + foreach my $new_obj_idx (@new_obj_idx) { + my $o = $self->{model}->objects->[$new_obj_idx]; + $o->clear_instances; + $o->add_instance($_) for @{$model_object->instances}; + #$o->invalidate_bounding_box; + + if ($o->volumes_count == $model_object->volumes_count) { + for my $i (0..($o->volumes_count-1)) { + $o->get_volume($i)->config->apply($model_object->get_volume($i)->config); + } + } + #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid, + } + + $self->remove($obj_idx); +*/ } void Plater::priv::item_changed_selection() @@ -1683,12 +1725,81 @@ void Plater::priv::on_progress_event() void Plater::priv::on_update_print_preview(wxCommandEvent &) { - // TODO + if (this->preview != nullptr) + this->preview->reload_print(); + // in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: +#if !ENABLE_EXTENDED_SELECTION + auto selections = p->collect_selections(); + _3DScene::set_objects_selections(p->canvas3D, selections); + if (p->canvas3D) + _3DScene::reload_scene(p->canvas3D, true); +#endif // !ENABLE_EXTENDED_SELECTION } void Plater::priv::on_process_completed(wxCommandEvent &) { - // TODO + // Stop the background task, wait until the thread goes into the "Idle" state. + // At this point of time the thread should be either finished or canceled, + // so the following call just confirms, that the produced data were consumed. + this->background_process.stop(); + //$self->statusbar->ResetCancelCallback(); + //$self->statusbar->StopBusy; + //$self->statusbar->SetStatusText(""); + +/* + my $message; + my $send_gcode = 0; + my $do_print = 0; +# print "Process completed, message: ", $message, "\n"; + if (defined($result)) { + $message = L("Export failed"); + } else { + # G-code file exported successfully. + if ($self->{print_file}) { + $message = L("File added to print queue"); + $do_print = 1; + } elsif ($self->{send_gcode_file}) { + $message = L("Sending G-code file to the Printer Host ..."); + $send_gcode = 1; + } elsif (defined $self->{export_gcode_output_file}) { + $message = L("G-code file exported to ") . $self->{export_gcode_output_file}; + } else { + $message = L("Slicing complete"); + } + } + $self->{export_gcode_output_file} = undef; + wxTheApp->notify($message); + + $self->do_print if $do_print; + + # Send $self->{send_gcode_file} to OctoPrint. + if ($send_gcode) { + my $host = Slic3r::PrintHost::get_print_host($self->{config}); + if ($host->send_gcode($self->{send_gcode_file})) { + $message = L("Upload to host finished."); + } else { + $message = ""; + } + } +*/ + + // As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm, + // but the "Processing finished" message is posted to this window. + // Delay the following status bar update, so it will be called later than what is received by MainFrame.pm. + //wxTheApp->CallAfter(sub { +// $self->statusbar->SetStatusText($message); +// }); + + //$self->{print_file} = undef; + //$self->{send_gcode_file} = undef; + //$self->print_info_box_show(1); + + // this updates buttons status + //$self->object_list_changed; + + // refresh preview + if (this->preview != nullptr) + this->preview->reload_print(); } void Plater::priv::on_layer_editing_toggled(bool enable) @@ -2190,7 +2301,22 @@ void Plater::export_3mf() void Plater::reslice() { - // TODO + // explicitly cancel a previous thread and start a new one. + // Don't reslice if export of G-code or sending to OctoPrint is running. +// if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) { + // Stop the background processing threads, stop the async update timer. + this->p->stop_background_process(); + // Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. + this->p->async_apply_config(); +/* + $self->statusbar->SetCancelCallback(sub { + $self->stop_background_process; + $self->statusbar->SetStatusText(L("Slicing cancelled")); + # this updates buttons status + $self->object_list_changed; + }); +*/ + this->p->start_background_process(); } void Plater::send_gcode()