diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index c9953e38a..b00000d08 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -127,6 +127,8 @@ add_library(libslic3r STATIC PolylineCollection.hpp Print.cpp Print.hpp + PrintBase.cpp + PrintBase.hpp PrintExport.hpp PrintConfig.cpp PrintConfig.hpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b6752147b..4f1ec05af 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -373,11 +373,10 @@ std::vector>> GCode::collec size_t layer_idx; }; - PrintObjectPtrs printable_objects = print.get_printable_objects(); - std::vector> per_object(printable_objects.size(), std::vector()); + std::vector> per_object(print.objects().size(), std::vector()); std::vector ordering; - for (size_t i = 0; i < printable_objects.size(); ++i) { - per_object[i] = collect_layers_to_print(*printable_objects[i]); + for (size_t i = 0; i < print.objects().size(); ++i) { + per_object[i] = collect_layers_to_print(*print.objects()[i]); OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -402,7 +401,7 @@ std::vector>> GCode::collec std::pair> merged; // Assign an average print_z to the set of layers with nearly equal print_z. merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z); - merged.second.assign(printable_objects.size(), LayerToPrint()); + merged.second.assign(print.objects().size(), LayerToPrint()); for (; i < j; ++i) { const OrderingItem &oi = ordering[i]; assert(merged.second[oi.object_idx].layer() == nullptr); @@ -569,10 +568,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. m_layer_count = 0; - PrintObjectPtrs printable_objects = print.get_printable_objects(); if (print.config().complete_objects.value) { // Add each of the object's layers separately. - for (auto object : printable_objects) { + for (auto object : print.objects()) { std::vector zs; zs.reserve(object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) @@ -585,7 +583,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } else { // Print all objects with the same print_z together. std::vector zs; - for (auto object : printable_objects) { + for (auto object : print.objects()) { zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) zs.push_back(layer->print_z); @@ -608,7 +606,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) { // get the minimum cross-section used in the print std::vector mm3_per_mm; - for (auto object : printable_objects) { + for (auto object : print.objects()) { for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { const PrintRegion* region = print.regions()[region_id]; for (auto layer : object->layers()) { @@ -673,7 +671,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.throw_if_canceled(); // Write some terse information on the slicing parameters. - const PrintObject *first_object = printable_objects.front(); + const PrintObject *first_object = print.objects().front(); const double layer_height = first_object->config().layer_height.value; const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height); for (const PrintRegion* region : print.regions()) { @@ -711,8 +709,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) bool has_wipe_tower = false; if (print.config().complete_objects.value) { // Find the 1st printing object, find its tool ordering and the initial extruder ID. - for (; initial_print_object_id < printable_objects.size(); ++initial_print_object_id) { - tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], initial_extruder_id); + for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) { + tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id); if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) break; } @@ -796,7 +794,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Collect outer contours of all objects over all layers. // Discard objects only containing thin walls (offset would fail on an empty polygon). Polygons islands; - for (const PrintObject *object : printable_objects) + for (const PrintObject *object : print.objects()) for (const Layer *layer : object->layers()) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->copies()) { @@ -849,7 +847,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) if (print.config().complete_objects.value) { // Print objects from the smallest to the tallest to avoid collisions // when moving onto next object starting point. - std::vector objects(printable_objects); + std::vector objects(print.objects()); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); }); size_t finished_objects = 0; for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { @@ -912,8 +910,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Order objects using a nearest neighbor search. std::vector object_indices; Points object_reference_points; - PrintObjectPtrs printable_objects = print.get_printable_objects(); - for (PrintObject *object : printable_objects) + for (PrintObject *object : print.objects()) object_reference_points.push_back(object->copies().front()); Slic3r::Geometry::chained_path(object_reference_points, object_indices); // Sort layers by Z. @@ -928,7 +925,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Verify, whether the print overaps the priming extrusions. BoundingBoxf bbox_print(get_print_extrusions_extents(print)); coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : printable_objects) + for (const PrintObject *print_object : print.objects()) bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 3793051f4..e800cd53f 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -68,12 +68,11 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool { m_print_config_ptr = &print.config(); - PrintObjectPtrs objects = print.get_printable_objects(); // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { std::vector zs; - for (auto object : objects) { + for (auto object : print.objects()) { zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) zs.emplace_back(layer->print_z); @@ -86,7 +85,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } // Collect extruders reuqired to print the layers. - for (auto object : objects) + for (auto object : print.objects()) this->collect_extruders(*object); // Reorder the extruders to minimize tool switches. @@ -451,7 +450,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: - PrintObjectPtrs object_list = print.get_printable_objects(); + PrintObjectPtrs object_list = print.objects(); std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().wipe_into_objects; }); // We will now iterate through @@ -547,8 +546,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config()); unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config()); - PrintObjectPtrs printable_objects = print.get_printable_objects(); - for (const PrintObject* object : printable_objects) { + for (const PrintObject* object : print.objects()) { // Finds this layer: auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers().end()) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b965f09ba..a40c4e7d6 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -188,8 +188,9 @@ public: when user expects that. */ Vec3d origin_translation; - Model* get_model() const { return m_model; }; - + Model* get_model() { return m_model; }; + const Model* get_model() const { return m_model; }; + ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 41e5f067d..7c876d72e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -25,33 +25,27 @@ namespace Slic3r { template class PrintState; template class PrintState; -void Print::clear_objects() +void Print::clear() { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); + // The following call should stop background processing if it is running. + this->invalidate_all_steps(); for (PrintObject *object : m_objects) delete object; m_objects.clear(); for (PrintRegion *region : m_regions) delete region; m_regions.clear(); - this->invalidate_all_steps(); -} - -void Print::delete_object(size_t idx) -{ - tbb::mutex::scoped_lock lock(m_mutex); - // destroy object and remove it from our container - delete m_objects[idx]; - m_objects.erase(m_objects.begin() + idx); - this->invalidate_all_steps(); - // TODO: purge unused regions } +// Only used by the Perl test cases. void Print::reload_object(size_t /* idx */) { ModelObjectPtrs model_objects; { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); + // The following call should stop background processing if it is running. + this->invalidate_all_steps(); /* TODO: this method should check whether the per-object config and per-material configs have changed in such a way that regions need to be rearranged or we can just apply the diff and invalidate something. Same logic as apply_config() @@ -68,33 +62,12 @@ void Print::reload_object(size_t /* idx */) for (PrintRegion *region : m_regions) delete region; m_regions.clear(); - this->invalidate_all_steps(); } // re-add model objects for (ModelObject *mo : model_objects) this->add_model_object(mo); } -// Reloads the model instances into the print class. -// The slicing shall not be running as the modified model instances at the print -// are used for the brim & skirt calculation. -// Returns true if the brim or skirt have been invalidated. -bool Print::reload_model_instances() -{ - tbb::mutex::scoped_lock lock(m_mutex); - bool invalidated = false; - for (PrintObject *object : m_objects) - invalidated |= object->reload_model_instances(); - return invalidated; -} - -PrintObjectPtrs Print::get_printable_objects() const -{ - PrintObjectPtrs printable_objects(m_objects); - printable_objects.erase(std::remove_if(printable_objects.begin(), printable_objects.end(), [](PrintObject* o) { return !o->is_printable(); }), printable_objects.end()); - return printable_objects; -} - PrintRegion* Print::add_region() { m_regions.emplace_back(new PrintRegion(this)); @@ -282,11 +255,11 @@ bool Print::invalidate_state_by_config_options(const std::vectorcancel_mutex()); // Initialize a new print object and store it at the given position. - PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *object = new PrintObject(this, model_object); if (idx != -1) { delete m_objects[idx]; m_objects[idx] = object; @@ -460,7 +433,7 @@ void Print::add_model_object(ModelObject* model_object, int idx) bool Print::apply_config(DynamicPrintConfig config) { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); // we get a copy of the config object so we can modify it safely config.normalize(); @@ -560,7 +533,7 @@ exit_for_rearrange_regions: model_objects.reserve(m_objects.size()); for (PrintObject *object : m_objects) model_objects.push_back(object->model_object()); - this->clear_objects(); + this->clear(); for (ModelObject *mo : model_objects) this->add_model_object(mo); invalidated = true; @@ -786,7 +759,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(false); // Grab the lock for the Print / PrintObject milestones. - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); // The following call may stop the background processing. update_apply_status(this->invalidate_state_by_config_options(print_diff)); @@ -823,7 +796,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (model.id() != m_model.id()) { // Kill everything, initialize from scratch. // Stop background processing. - m_cancel_callback(); + this->call_cancell_callback(); update_apply_status(this->invalidate_all_steps()); for (PrintObject *object : m_objects) { model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); @@ -854,7 +827,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } else { // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. - m_cancel_callback(); + this->call_cancell_callback(); this->invalidate_step(psGCodeExport); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); @@ -964,7 +937,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co model_object.assign_copy(model_object_new); } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. - m_cancel_callback(); + this->call_cancell_callback(); // Invalidate just the supports step. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) @@ -1024,7 +997,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (old.empty()) { // Simple case, just generate new instances. for (const PrintInstances &print_instances : new_print_instances) { - PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *print_object = new PrintObject(this, model_object); print_object->set_trafo(print_instances.trafo); print_object->set_copies(print_instances.copies); print_object->config_apply(config); @@ -1043,7 +1016,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co for (; it_old != old.end() && transform3d_lower((*it_old)->trafo, new_instances.trafo); ++ it_old); if (it_old == old.end() || ! transform3d_equal((*it_old)->trafo, new_instances.trafo)) { // This is a new instance (or a set of instances with the same trafo). Just add it. - PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *print_object = new PrintObject(this, model_object); print_object->set_trafo(new_instances.trafo); print_object->set_copies(new_instances.copies); print_object->config_apply(config); @@ -1066,7 +1039,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } } if (m_objects != print_objects_new) { - m_cancel_callback(); + this->call_cancell_callback(); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. bool deleted_objects = false; @@ -1562,7 +1535,7 @@ void Print::process() for (PrintObject *obj : m_objects) obj->generate_support_material(); this->throw_if_canceled(); - if (! m_state.is_done(psSkirt)) { + if (! this->is_step_done(psSkirt)) { this->set_started(psSkirt); m_skirt.clear(); if (this->has_skirt()) { @@ -1572,7 +1545,7 @@ void Print::process() this->set_done(psSkirt); } this->throw_if_canceled(); - if (! m_state.is_done(psBrim)) { + if (! this->is_step_done(psBrim)) { this->set_started(psBrim); m_brim.clear(); if (m_config.brim_width > 0) { @@ -1582,7 +1555,7 @@ void Print::process() this->set_done(psBrim); } this->throw_if_canceled(); - if (! m_state.is_done(psWipeTower)) { + if (! this->is_step_done(psWipeTower)) { this->set_started(psWipeTower); m_wipe_tower_data.clear(); if (this->has_wipe_tower()) { @@ -1631,8 +1604,7 @@ void Print::_make_skirt() // prepended to the first 'n' layers (with 'n' = skirt_height). // $skirt_height_z in this case is the highest possible skirt height for safety. coordf_t skirt_height_z = 0.; - PrintObjectPtrs printable_objects = get_printable_objects(); - for (const PrintObject *object : printable_objects) { + for (const PrintObject *object : m_objects) { size_t skirt_layers = this->has_infinite_skirt() ? object->layer_count() : std::min(size_t(m_config.skirt_height.value), object->layer_count()); @@ -1641,7 +1613,7 @@ void Print::_make_skirt() // Collect points from all layers contained in skirt height. Points points; - for (const PrintObject *object : printable_objects) { + for (const PrintObject *object : m_objects) { Points object_points; // Get object layers up to skirt_height_z. for (const Layer *layer : object->m_layers) { @@ -1756,8 +1728,7 @@ void Print::_make_brim() // Brim is only printed on first layer and uses perimeter extruder. Flow flow = this->brim_flow(); Polygons islands; - PrintObjectPtrs printable_objects = get_printable_objects(); - for (PrintObject *object : printable_objects) { + for (PrintObject *object : m_objects) { Polygons object_islands; for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons) object_islands.push_back(expoly.contour); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 705c41458..dbf07369b 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1,15 +1,10 @@ #ifndef slic3r_Print_hpp_ #define slic3r_Print_hpp_ -#include "libslic3r.h" -#include -#include -#include -#include -#include +#include "PrintBase.hpp" + #include "BoundingBox.hpp" #include "Flow.hpp" -#include "PrintConfig.hpp" #include "Point.hpp" #include "Layer.hpp" #include "Model.hpp" @@ -18,13 +13,6 @@ #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" -#include "tbb/atomic.h" -// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros. -#ifndef NOMINMAX - #define NOMINMAX -#endif -#include "tbb/mutex.h" - namespace Slic3r { class Print; @@ -42,116 +30,6 @@ enum PrintObjectStep { posInfill, posSupportMaterial, posCount, }; -class CanceledException : public std::exception { -public: - const char* what() const throw() { return "Background processing has been canceled"; } -}; - -// To be instantiated over PrintStep or PrintObjectStep enums. -template -class PrintState -{ -public: - PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); } - - enum State { - INVALID, - STARTED, - DONE, - }; - - // With full memory barrier. - bool is_done(StepType step) const { return m_state[step] == DONE; } - - // Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being - // modified by the UI thread. - // This is necessary to block until the Print::apply_config() updates its state, which may - // influence the processing step being entered. - void set_started(StepType step, tbb::mutex &mtx) { - mtx.lock(); - m_state[step].store(STARTED, std::memory_order_relaxed); - mtx.unlock(); - } - - // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being - // modified by the UI thread. - void set_done(StepType step, tbb::mutex &mtx) { - mtx.lock(); - m_state[step].store(DONE, std::memory_order_relaxed); - mtx.unlock(); - } - - // Make the step invalid. - // The provided mutex should be locked at this point, guarding access to m_state. - // In case the step has already been entered or finished, cancel the background - // processing by calling the cancel callback. - template - bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID; - if (invalidated) { -#if 0 - if (mtx.state != mtx.HELD) { - printf("Not held!\n"); - } -#endif - // Raise the mutex, so that the following cancel() callback could cancel - // the background processing. - mtx.unlock(); - cancel(); - m_state[step] = INVALID; - mtx.lock(); - } - return invalidated; - } - - template - bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = false; - for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it) - invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID; - if (invalidated) { -#if 0 - if (mtx.state != mtx.HELD) { - printf("Not held!\n"); - } -#endif - // Raise the mutex, so that the following cancel() callback could cancel - // the background processing. - mtx.unlock(); - cancel(); - for (StepTypeIterator it = step_begin; it != step_end; ++ it) - m_state[*it] = INVALID; - mtx.lock(); - } - return invalidated; - } - - // Make all steps invalid. - // The provided mutex should be locked at this point, guarding access to m_state. - // In case any step has already been entered or finished, cancel the background - // processing by calling the cancel callback. - template - bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = false; - for (size_t i = 0; i < COUNT; ++ i) - if (m_state[i].load(std::memory_order_relaxed) != INVALID) { - invalidated = true; - break; - } - if (invalidated) { - mtx.unlock(); - cancel(); - for (size_t i = 0; i < COUNT; ++ i) - m_state[i].store(INVALID, std::memory_order_relaxed); - mtx.lock(); - } - return invalidated; - } - -private: - std::atomic m_state[COUNT]; -}; - // A PrintRegion object represents a group of volumes to print // sharing the same config (including the same assigned extruder(s)) class PrintRegion @@ -193,9 +71,10 @@ typedef std::vector LayerPtrs; typedef std::vector SupportLayerPtrs; class BoundingBoxf3; // TODO: for temporary constructor parameter -class PrintObject +class PrintObject : public PrintObjectBaseWithState { - friend class Print; +private: // Prevents erroneous use by other classes. + typedef PrintObjectBaseWithState Inherited; public: // vector of (vectors of volume ids), indexed by region_id @@ -218,25 +97,13 @@ public: Vec3crd size; // XYZ in scaled coordinates - Print* print() { return m_print; } - const Print* print() const { return m_print; } - ModelObject* model_object() { return m_model_object; } const ModelObject* model_object() const { return m_model_object; } + ModelObject* model_object() { return m_model_object; } const PrintObjectConfig& config() const { return m_config; } - void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } - void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } const LayerPtrs& layers() const { return m_layers; } const SupportLayerPtrs& support_layers() const { return m_support_layers; } - const Transform3d& trafo() const { return m_trafo; } - void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } - const Points& copies() const { return m_copies; } - bool add_copy(const Vec2d &point); - bool delete_last_copy(); - bool delete_all_copies() { return this->set_copies(Points()); } - bool set_copies(const Points &points); - bool reload_model_instances(); // since the object is aligned to origin, bounding box coincides with size BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); } @@ -268,12 +135,6 @@ public: // methods for handling state bool invalidate_state_by_config_options(const std::vector &opt_keys); - bool invalidate_step(PrintObjectStep step); - template - bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); } - bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); } - bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); } - bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); } // To be used over the layer_height_profile of both the PrintObject and ModelObject // to initialize the height profile with the height ranges. @@ -300,6 +161,20 @@ public: std::vector slice_support_enforcers() const; std::vector slice_support_blockers() const; +protected: + // to be called from Print only. + friend class Print; + + PrintObject(Print* print, ModelObject* model_object); + ~PrintObject() {} + + void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } + void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } + void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } + bool set_copies(const Points &points); + // Invalidates the step, and its depending steps in PrintObject and Print. + bool invalidate_step(PrintObjectStep step); + private: void make_perimeters(); void prepare_infill(); @@ -320,12 +195,6 @@ private: void combine_infill(); void _generate_support_material(); - bool is_printable() const { return ! m_copies.empty(); } - // Implemented in cpp due to cyclic dependencies between Print and PrintObject. - tbb::mutex& cancel_mutex(); - std::function cancel_callback(); - - Print *m_print; ModelObject *m_model_object; PrintObjectConfig m_config; // Translation in Z + Rotation + Scaling / Mirroring. @@ -340,15 +209,6 @@ private: LayerPtrs m_layers; SupportLayerPtrs m_support_layers; - PrintState m_state; - - // TODO: call model_object->get_bounding_box() instead of accepting - // parameter - PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox); - ~PrintObject() {} - - void set_started(PrintObjectStep step); - void set_done(PrintObjectStep step); std::vector _slice_region(size_t region_id, const std::vector &z, bool modifier); std::vector _slice_volumes(const std::vector &z, const std::vector &volumes) const; }; @@ -410,33 +270,30 @@ typedef std::vector PrintObjectPtrs; typedef std::vector PrintRegionPtrs; // The complete print tray with possibly multiple objects. -class Print +class Print : public PrintBaseWithState { +private: // Prevents erroneous use by other classes. + typedef PrintBaseWithState Inherited; + public: - Print() { restart(); } - ~Print() { clear_objects(); } + Print() {} + virtual ~Print() { this->clear(); } + + PrinterTechnology technology() const noexcept { return ptFFF; } // Methods, which change the state of Print / PrintObject / PrintRegion. // The following methods are synchronized with process() and export_gcode(), // so that process() and export_gcode() may be called from a background thread. // In case the following methods need to modify data processed by process() or export_gcode(), // a cancellation callback is executed to stop the background processing before the operation. - void clear_objects(); - void delete_object(size_t idx); + void clear() override; + + ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + + // The following three methods are used by the Perl tests only. Get rid of them! void reload_object(size_t idx); - bool reload_model_instances(); void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig config); - enum ApplyStatus { - // No change after the Print::apply() call. - APPLY_STATUS_UNCHANGED, - // Some of the Print / PrintObject / PrintObjectInstance data was changed, - // but no result was invalidated (only data influencing not yet calculated results were changed). - APPLY_STATUS_CHANGED, - // Some data was changed, which in turn invalidated already calculated steps. - APPLY_STATUS_INVALIDATED, - }; - ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); void process(); void export_gcode(const std::string &path_template, GCodePreviewData *preview_data); @@ -444,12 +301,11 @@ public: void export_png(const std::string &dirpath); // methods for handling state - bool is_step_done(PrintStep step) const { return m_state.is_done(step); } + bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); } bool is_step_done(PrintObjectStep step) const; bool has_infinite_skirt() const; bool has_skirt() const; - PrintObjectPtrs get_printable_objects() const; float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; } // Returns an empty string if valid, otherwise returns an error message. @@ -482,7 +338,7 @@ public: unsigned int num_object_instances() const; // Returns extruder this eec should be printed with, according to PrintRegion config: - static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); + static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } @@ -496,69 +352,24 @@ public: std::string output_filename() const; std::string output_filepath(const std::string &path) const; - typedef std::function status_callback_type; - // Default status console print out in the form of percent => message. - void set_status_default() { m_status_callback = nullptr; } - // No status output or callback whatsoever, useful mostly for automatic tests. - void set_status_silent() { m_status_callback = [](int, const std::string&){}; } - // Register a custom status callback. - void set_status_callback(status_callback_type cb) { m_status_callback = cb; } - // Calls a registered callback to update the status, or print out the default message. - void set_status(int percent, const std::string &message) { - if (m_status_callback) m_status_callback(percent, message); - else printf("%d => %s\n", percent, message.c_str()); - } - - typedef std::function cancel_callback_type; - // Various methods will call this callback to stop the background processing (the Print::process() call) - // in case a successive change of the Print / PrintObject / PrintRegion instances changed - // the state of the finished or running calculations. - void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } - // Has the calculation been canceled? - enum CancelStatus { - // No cancelation, background processing should run. - NOT_CANCELED = 0, - // Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application). - CANCELED_BY_USER = 1, - // Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps(). - CANCELED_INTERNAL = 2 - }; - CancelStatus cancel_status() const { return m_cancel_status; } - // Has the calculation been canceled? - bool canceled() const { return m_cancel_status != NOT_CANCELED; } - // Cancel the running computation. Stop execution of all the background threads. - void cancel() { m_cancel_status = CANCELED_BY_USER; } - void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } - // Cancel the running computation. Stop execution of all the background threads. - void restart() { m_cancel_status = NOT_CANCELED; } - // Accessed by SupportMaterial const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } protected: - void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); } - void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); } - bool invalidate_step(PrintStep step); - template - bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } - bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), m_mutex, m_cancel_callback); } - bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); } - // methods for handling regions PrintRegion* get_region(size_t idx) { return m_regions[idx]; } PrintRegion* add_region(); PrintRegion* add_region(const PrintRegionConfig &config); + // Invalidates the step, and its depending steps in Print. + bool invalidate_step(PrintStep step); + private: // Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects. void update_object_placeholders(); bool invalidate_state_by_config_options(const std::vector &opt_keys); - // 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. - void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); } - void _make_skirt(); void _make_brim(); void _make_wipe_tower(); @@ -567,19 +378,6 @@ private: // Declared here to have access to Model / ModelObject / ModelInstance static void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src); - PrintState m_state; - // Mutex used for synchronization of the worker thread with the UI thread: - // The mutex will be used to guard the worker thread against entering a stage - // while the data influencing the stage is modified. - mutable tbb::mutex m_mutex; - - tbb::atomic m_cancel_status; - // Callback to be evoked regularly to update state of the UI thread. - status_callback_type m_status_callback; - - // Callback to be evoked to stop the background processing before a state is updated. - cancel_callback_type m_cancel_callback = [](){}; - Model m_model; PrintConfig m_config; PrintObjectConfig m_default_object_config; @@ -604,6 +402,6 @@ private: friend class PrintObject; }; -} +} /* slic3r_Print_hpp_ */ #endif diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp new file mode 100644 index 000000000..d4fffca94 --- /dev/null +++ b/src/libslic3r/PrintBase.cpp @@ -0,0 +1,16 @@ +#include "PrintBase.hpp" + +namespace Slic3r +{ + +tbb::mutex& PrintObjectBase::cancel_mutex(PrintBase *print) +{ + return print->cancel_mutex(); +} + +std::function PrintObjectBase::cancel_callback(PrintBase *print) +{ + return print->cancel_callback(); +} + +} // namespace Slic3r diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp new file mode 100644 index 000000000..47a849e84 --- /dev/null +++ b/src/libslic3r/PrintBase.hpp @@ -0,0 +1,297 @@ +#ifndef slic3r_PrintBase_hpp_ +#define slic3r_PrintBase_hpp_ + +#include "libslic3r.h" +#include +#include +#include +#include +#include + +#include "tbb/atomic.h" +// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros. +#ifndef NOMINMAX + #define NOMINMAX +#endif +#include "tbb/mutex.h" + +#include "Model.hpp" +#include "PrintConfig.hpp" + +namespace Slic3r { + +class CanceledException : public std::exception { +public: + const char* what() const throw() { return "Background processing has been canceled"; } +}; + +// To be instantiated over PrintStep or PrintObjectStep enums. +template +class PrintState +{ +public: + PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); } + + enum State { + INVALID, + STARTED, + DONE, + }; + + // With full memory barrier. + bool is_done(StepType step) const { return m_state[step] == DONE; } + + // Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. + // This is necessary to block until the Print::apply_config() updates its state, which may + // influence the processing step being entered. + void set_started(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(STARTED, std::memory_order_relaxed); + mtx.unlock(); + } + + // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. + void set_done(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(DONE, std::memory_order_relaxed); + mtx.unlock(); + } + + // Make the step invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case the step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template + bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { +#if 0 + if (mtx.state != mtx.HELD) { + printf("Not held!\n"); + } +#endif + // Raise the mutex, so that the following cancel() callback could cancel + // the background processing. + mtx.unlock(); + cancel(); + m_state[step] = INVALID; + mtx.lock(); + } + return invalidated; + } + + template + bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = false; + for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it) + invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { +#if 0 + if (mtx.state != mtx.HELD) { + printf("Not held!\n"); + } +#endif + // Raise the mutex, so that the following cancel() callback could cancel + // the background processing. + mtx.unlock(); + cancel(); + for (StepTypeIterator it = step_begin; it != step_end; ++ it) + m_state[*it] = INVALID; + mtx.lock(); + } + return invalidated; + } + + // Make all steps invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case any step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template + bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = false; + for (size_t i = 0; i < COUNT; ++ i) + if (m_state[i].load(std::memory_order_relaxed) != INVALID) { + invalidated = true; + break; + } + if (invalidated) { + mtx.unlock(); + cancel(); + for (size_t i = 0; i < COUNT; ++ i) + m_state[i].store(INVALID, std::memory_order_relaxed); + mtx.lock(); + } + return invalidated; + } + +private: + std::atomic m_state[COUNT]; +}; + +class PrintBase; + +class PrintObjectBase +{ +protected: + virtual ~PrintObjectBase() {} + // Declared here to allow access from PrintBase through friendship. + static tbb::mutex& cancel_mutex(PrintBase *print); + static std::function cancel_callback(PrintBase *print); +}; + +/** + * @brief Printing involves slicing and export of device dependent instructions. + * + * Every technology has a potentially different set of requirements for + * slicing, support structures and output print instructions. The pipeline + * however remains roughly the same: + * slice -> convert to instructions -> send to printer + * + * The PrintBase class will abstract this flow for different technologies. + * + */ +class PrintBase +{ +public: + PrintBase() { this->restart(); } + inline virtual ~PrintBase() {} + + virtual PrinterTechnology technology() const noexcept = 0; + + // Reset the print status including the copy of the Model / ModelObject hierarchy. + virtual void clear() = 0; + + enum ApplyStatus { + // No change after the Print::apply() call. + APPLY_STATUS_UNCHANGED, + // Some of the Print / PrintObject / PrintObjectInstance data was changed, + // but no result was invalidated (only data influencing not yet calculated results were changed). + APPLY_STATUS_CHANGED, + // Some data was changed, which in turn invalidated already calculated steps. + APPLY_STATUS_INVALIDATED, + }; + virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; + + virtual void process() = 0; + + typedef std::function status_callback_type; + // Default status console print out in the form of percent => message. + void set_status_default() { m_status_callback = nullptr; } + // No status output or callback whatsoever, useful mostly for automatic tests. + void set_status_silent() { m_status_callback = [](int, const std::string&){}; } + // Register a custom status callback. + void set_status_callback(status_callback_type cb) { m_status_callback = cb; } + // Calls a registered callback to update the status, or print out the default message. + void set_status(int percent, const std::string &message) { + if (m_status_callback) m_status_callback(percent, message); + else printf("%d => %s\n", percent, message.c_str()); + } + + typedef std::function cancel_callback_type; + // Various methods will call this callback to stop the background processing (the Print::process() call) + // in case a successive change of the Print / PrintObject / PrintRegion instances changed + // the state of the finished or running calculations. + void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } + // Has the calculation been canceled? + enum CancelStatus { + // No cancelation, background processing should run. + NOT_CANCELED = 0, + // Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application). + CANCELED_BY_USER = 1, + // Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps(). + CANCELED_INTERNAL = 2 + }; + CancelStatus cancel_status() const { return m_cancel_status; } + // Has the calculation been canceled? + bool canceled() const { return m_cancel_status != NOT_CANCELED; } + // Cancel the running computation. Stop execution of all the background threads. + void cancel() { m_cancel_status = CANCELED_BY_USER; } + void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } + // Cancel the running computation. Stop execution of all the background threads. + void restart() { m_cancel_status = NOT_CANCELED; } + +protected: + friend class PrintObjectBase; + + tbb::mutex& cancel_mutex() { return m_cancel_mutex; } + std::function cancel_callback() { return m_cancel_callback; } + void call_cancell_callback() { m_cancel_callback(); } + + // 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. + void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); } + +private: + tbb::atomic m_cancel_status; + // Callback to be evoked regularly to update state of the UI thread. + status_callback_type m_status_callback; + + // Callback to be evoked to stop the background processing before a state is updated. + cancel_callback_type m_cancel_callback = [](){}; + + // Mutex used for synchronization of the worker thread with the UI thread: + // The mutex will be used to guard the worker thread against entering a stage + // while the data influencing the stage is modified. + mutable tbb::mutex m_cancel_mutex; +}; + +template +class PrintBaseWithState : public PrintBase +{ +public: + bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step); } + +protected: + void set_started(PrintStepEnum step) { m_state.set_started(step, this->cancel_mutex()); throw_if_canceled(); } + void set_done(PrintStepEnum step) { m_state.set_done(step, this->cancel_mutex()); throw_if_canceled(); } + bool invalidate_step(PrintStepEnum step) + { return m_state.invalidate(step, this->cancel_mutex(), this->cancel_callback()); } + template + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) + { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_steps(std::initializer_list il) + { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_all_steps() + { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); } + +private: + PrintState m_state; +}; + +template +class PrintObjectBaseWithState : public PrintObjectBase +{ +public: + Print* print() { return m_print; } + const Print* print() const { return m_print; } + + bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step); } + +protected: + PrintObjectBaseWithState(PrintType *print) : m_print(print) {} + + void set_started(PrintObjectStepEnum step) { m_state.set_started(step, PrintObjectBase::cancel_mutex(m_print)); } + void set_done(PrintObjectStepEnum step) { m_state.set_done(step, PrintObjectBase::cancel_mutex(m_print)); } + + bool invalidate_step(PrintObjectStepEnum step) + { return m_state.invalidate(step, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + template + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) + { return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + bool invalidate_steps(std::initializer_list il) + { return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + +protected: + friend typename PrintType; + PrintType *m_print; + +private: + PrintState m_state; +}; + +} // namespace Slic3r + +#endif /* slic3r_PrintBase_hpp_ */ diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 45b2689bb..f0361ba01 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -34,9 +34,9 @@ namespace Slic3r { -PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) : +PrintObject::PrintObject(Print* print, ModelObject* model_object) : + PrintObjectBaseWithState(print), typed_slices(false), - m_print(print), m_model_object(model_object), size(Vec3crd::Zero()), layer_height_profile_valid(false) @@ -49,42 +49,27 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding // don't assume it's already aligned and we don't alter the original position in model. // We store the XY translation so that we can place copies correctly in the output G-code // (copies are expressed in G-code coordinates and this translation is not publicly exposed). + const BoundingBoxf3 modobj_bbox = model_object->raw_bounding_box(); m_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1)); // Scale the object size and store it this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast(); } - this->reload_model_instances(); + { + Points copies; + copies.reserve(m_model_object->instances.size()); + for (const ModelInstance *mi : m_model_object->instances) { + assert(mi->is_printable()); + const Vec3d& offset = mi->get_offset(); + copies.emplace_back(Point::new_scale(offset(0), offset(1))); + } + this->set_copies(copies); + } + this->layer_height_ranges = model_object->layer_height_ranges; this->layer_height_profile = model_object->layer_height_profile; } -void PrintObject::set_started(PrintObjectStep step) -{ - m_state.set_started(step, m_print->m_mutex); -} - -void PrintObject::set_done(PrintObjectStep step) -{ - m_state.set_done(step, m_print->m_mutex); -} - -bool PrintObject::add_copy(const Vec2d &point) -{ - tbb::mutex::scoped_lock lock(m_print->m_mutex); - Points points = m_copies; - points.push_back(Point::new_scale(point(0), point(1))); - return this->set_copies(points); -} - -bool PrintObject::delete_last_copy() -{ - tbb::mutex::scoped_lock lock(m_print->m_mutex); - Points points = m_copies; - points.pop_back(); - return this->set_copies(points); -} - bool PrintObject::set_copies(const Points &points) { // Order copies with a nearest-neighbor search. @@ -107,21 +92,6 @@ bool PrintObject::set_copies(const Points &points) return invalidated; } -bool PrintObject::reload_model_instances() -{ - Points copies; - copies.reserve(m_model_object->instances.size()); - for (const ModelInstance *mi : m_model_object->instances) - { - if (mi->is_printable()) - { - const Vec3d& offset = mi->get_offset(); - copies.emplace_back(Point::new_scale(offset(0), offset(1))); - } - } - return this->set_copies(copies); -} - // 1) Decides Z positions of the layers, // 2) Initializes layers and their regions // 3) Slices the object meshes @@ -388,9 +358,6 @@ void PrintObject::prepare_infill() void PrintObject::infill() { - if (! this->is_printable()) - return; - // prerequisites this->prepare_infill(); @@ -583,7 +550,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorm_mutex, m_print->m_cancel_callback); + bool invalidated = Inherited::invalidate_step(step); // propagate to dependent steps if (step == posPerimeters) { @@ -1732,9 +1699,6 @@ void PrintObject::_simplify_slices(double distance) void PrintObject::_make_perimeters() { - if (!this->is_printable()) - return; - if (this->is_step_done(posPerimeters)) return; this->set_started(posPerimeters); @@ -2226,9 +2190,6 @@ void PrintObject::combine_infill() void PrintObject::_generate_support_material() { - if (!this->is_printable()) - return; - PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters()); support_material.generate(*this); } @@ -2251,15 +2212,4 @@ void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickne layer_height_profile_valid = false; } -tbb::mutex& PrintObject::cancel_mutex() -{ - return m_print->m_mutex; -} - -std::function PrintObject::cancel_callback() -{ - return m_print->m_cancel_callback; -} - - } // namespace Slic3r diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 441a6ab80..e9fa54ce0 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -216,12 +216,10 @@ int main(int argc, char **argv) } if (outfile.empty()) outfile = model.objects.front()->input_file + ".gcode"; - for (auto* mo : model.objects) { + for (auto* mo : model.objects) print.auto_assign_extruders(mo); - print.add_model_object(mo); - } print_config.normalize(); - print.apply_config(print_config); + print.apply(model, print_config); std::string err = print.validate(); if (err.empty()) print.export_gcode(outfile, nullptr); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index cd438ebe5..62a6bb8a8 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -178,6 +178,14 @@ bool BackgroundSlicingProcess::stop() return true; } +bool BackgroundSlicingProcess::reset() +{ + bool stopped = this->stop(); + this->reset_export(); + m_print->clear(); + return stopped; +} + // To be called by Print::apply() through the Print::m_cancel_callback to stop the background // processing before changing any data of running or finalized milestones. // This function shall not trigger any UI update through the wxWidgets event. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 6b92e8516..6b589739e 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -43,6 +43,9 @@ public: // Cancel the background processing. Returns false if the background processing was not running. // A stopped background processing may be restarted with start(). bool stop(); + // Cancel the background processing and reset the print. Returns false if the background processing was not running. + // Useful when the Model or configuration is being changed drastically. + bool reset(); // 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. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7e91276d4..5927c270d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1434,8 +1434,9 @@ void Plater::priv::reset() if (_3DScene::is_layers_editing_enabled(canvas3D)) _3DScene::enable_layers_editing(canvas3D, false); + // Stop and reset the Print content. + this->background_process.reset(); model.clear_objects(); -// print.clear_objects(); // Delete all objects from list on c++ side sidebar->obj_list()->delete_all_objects_from_list(); @@ -2001,10 +2002,8 @@ void Plater::decrease_instances(size_t num) ModelObject* model_object = p->model.objects[obj_idx]; if (model_object->instances.size() > num) { - for (size_t i = 0; i < num; i++) { + for (size_t i = 0; i < num; ++ i) model_object->delete_last_instance(); -// p->print.get_object(obj_idx)->delete_last_copy(); - } sidebar().obj_list()->decrease_object_instances(obj_idx, num); } else { diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 11fa7e920..ffcb81def 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -92,10 +92,6 @@ bool store_stl(char *path, bool binary) %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; - bool store_amf(char *path, Print* print, bool export_print_config) - %code%{ RETVAL = Slic3r::store_amf(path, THIS, print, export_print_config); %}; - bool store_3mf(char *path, Print* print, bool export_print_config) - %code%{ RETVAL = Slic3r::store_3mf(path, THIS, print, export_print_config); %}; %{ diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index cf3b67931..f6edb5d64 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -58,10 +58,6 @@ _constant() Points _shifted_copies() %code%{ RETVAL = THIS->copies(); %}; - bool add_copy(Vec2d* point) - %code%{ RETVAL = THIS->add_copy(*point); %}; - bool delete_last_copy(); - bool reload_model_instances(); void set_layer_height_ranges(t_layer_height_ranges layer_height_ranges) %code%{ THIS->layer_height_ranges = layer_height_ranges; %}; @@ -109,12 +105,9 @@ _constant() %code%{ RETVAL = THIS->wipe_tower_data().number_of_toolchanges; %}; PrintObjectPtrs* objects() %code%{ RETVAL = const_cast(&THIS->objects()); %}; - void clear_objects(); Ref get_object(int idx) %code%{ RETVAL = THIS->objects()[idx]; %}; - void delete_object(int idx); void reload_object(int idx); - bool reload_model_instances(); size_t object_count() %code%{ RETVAL = THIS->objects().size(); %};