mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Separated Print / PrintObject into PrintBase.cpp/h to support SLAPrint
This commit is contained in:
		
							parent
							
								
									6d60ecffa0
								
							
						
					
					
						commit
						c2e46350f2
					
				
					 15 changed files with 433 additions and 406 deletions
				
			
		|  | @ -127,6 +127,8 @@ add_library(libslic3r STATIC | |||
|     PolylineCollection.hpp | ||||
|     Print.cpp | ||||
|     Print.hpp | ||||
|     PrintBase.cpp | ||||
|     PrintBase.hpp | ||||
|     PrintExport.hpp | ||||
|     PrintConfig.cpp | ||||
|     PrintConfig.hpp | ||||
|  |  | |||
|  | @ -373,11 +373,10 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec | |||
|         size_t      layer_idx; | ||||
|     }; | ||||
| 
 | ||||
|     PrintObjectPtrs printable_objects = print.get_printable_objects(); | ||||
|     std::vector<std::vector<LayerToPrint>>  per_object(printable_objects.size(), std::vector<LayerToPrint>()); | ||||
|     std::vector<std::vector<LayerToPrint>>  per_object(print.objects().size(), std::vector<LayerToPrint>()); | ||||
|     std::vector<OrderingItem>               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<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec | |||
|         std::pair<coordf_t, std::vector<LayerToPrint>> 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<coordf_t> 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<coordf_t> 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<double> 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<PrintObject*> objects(printable_objects); | ||||
|         std::vector<PrintObject*> 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<size_t> 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)); | ||||
|  |  | |||
|  | @ -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<coordf_t> 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)<EPSILON; }); | ||||
|         if (this_layer_it == object->layers().end()) | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -25,33 +25,27 @@ namespace Slic3r { | |||
| template class PrintState<PrintStep, psCount>; | ||||
| template class PrintState<PrintObjectStep, posCount>; | ||||
| 
 | ||||
| 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::vector<t_config_option | |||
| 
 | ||||
| bool Print::invalidate_step(PrintStep step) | ||||
| { | ||||
|     bool invalidated = m_state.invalidate(step, m_mutex, m_cancel_callback); | ||||
| 	bool invalidated = Inherited::invalidate_step(step); | ||||
|     // Propagate to dependent steps.
 | ||||
|     //FIXME Why should skirt invalidate brim? Shouldn't it be vice versa?
 | ||||
|     if (step == psSkirt) | ||||
|         invalidated |= m_state.invalidate(psBrim, m_mutex, m_cancel_callback); | ||||
| 		invalidated |= Inherited::invalidate_step(psBrim); | ||||
|     return invalidated; | ||||
| } | ||||
| 
 | ||||
|  | @ -399,9 +372,9 @@ static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig | |||
| // and have explicit instance positions.
 | ||||
| void Print::add_model_object(ModelObject* model_object, int idx) | ||||
| { | ||||
|     tbb::mutex::scoped_lock lock(m_mutex); | ||||
| 	tbb::mutex::scoped_lock lock(this->cancel_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<ModelObject*> 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); | ||||
|  |  | |||
|  | @ -1,15 +1,10 @@ | |||
| #ifndef slic3r_Print_hpp_ | ||||
| #define slic3r_Print_hpp_ | ||||
| 
 | ||||
| #include "libslic3r.h" | ||||
| #include <atomic> | ||||
| #include <set> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <functional> | ||||
| #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 StepType, size_t COUNT> | ||||
| 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<typename CancelationCallback> | ||||
|     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<typename CancelationCallback, typename StepTypeIterator> | ||||
| 	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<typename CancelationCallback> | ||||
|     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<State>          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<Layer*> LayerPtrs; | |||
| typedef std::vector<SupportLayer*> SupportLayerPtrs; | ||||
| class BoundingBoxf3;        // TODO: for temporary constructor parameter
 | ||||
| 
 | ||||
| class PrintObject | ||||
| class PrintObject : public PrintObjectBaseWithState<Print, PrintObjectStep, posCount> | ||||
| { | ||||
|     friend class Print; | ||||
| private: // Prevents erroneous use by other classes.
 | ||||
|     typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> 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<t_config_option_key> &opt_keys); | ||||
|     bool invalidate_step(PrintObjectStep step); | ||||
| 	template<typename StepTypeIterator> | ||||
| 	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<PrintObjectStep> 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<ExPolygons>     slice_support_enforcers() const; | ||||
|     std::vector<ExPolygons>     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<void()>  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<PrintObjectStep, posCount>   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<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier); | ||||
|     std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const; | ||||
| }; | ||||
|  | @ -410,33 +270,30 @@ typedef std::vector<PrintObject*> PrintObjectPtrs; | |||
| typedef std::vector<PrintRegion*> PrintRegionPtrs; | ||||
| 
 | ||||
| // The complete print tray with possibly multiple objects.
 | ||||
| class Print | ||||
| class Print : public PrintBaseWithState<PrintStep, psCount> | ||||
| { | ||||
| private: // Prevents erroneous use by other classes.
 | ||||
|     typedef PrintBaseWithState<PrintStep, psCount> 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<void(int, const std::string&)>  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<void()>  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<typename StepTypeIterator> | ||||
| 	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<PrintStep> 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<t_config_option_key> &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<PrintStep, psCount>          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<CancelStatus>               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 | ||||
|  |  | |||
							
								
								
									
										16
									
								
								src/libslic3r/PrintBase.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/libslic3r/PrintBase.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #include "PrintBase.hpp" | ||||
| 
 | ||||
| namespace Slic3r | ||||
| { | ||||
| 
 | ||||
| tbb::mutex& PrintObjectBase::cancel_mutex(PrintBase *print) | ||||
| {  | ||||
| 	return print->cancel_mutex(); | ||||
| } | ||||
| 
 | ||||
| std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print) | ||||
| {  | ||||
| 	return print->cancel_callback(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
							
								
								
									
										297
									
								
								src/libslic3r/PrintBase.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								src/libslic3r/PrintBase.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,297 @@ | |||
| #ifndef slic3r_PrintBase_hpp_ | ||||
| #define slic3r_PrintBase_hpp_ | ||||
| 
 | ||||
| #include "libslic3r.h" | ||||
| #include <atomic> | ||||
| #include <set> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <functional> | ||||
| 
 | ||||
| #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 StepType, size_t COUNT> | ||||
| 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<typename CancelationCallback> | ||||
|     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<typename CancelationCallback, typename StepTypeIterator> | ||||
|     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<typename CancelationCallback> | ||||
|     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<State>          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<void()>  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<void(int, const std::string&)>  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<void()>  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<void()>  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<CancelStatus>               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<typename PrintStepEnum, const size_t COUNT> | ||||
| 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<typename StepTypeIterator> | ||||
|     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<PrintStepEnum> 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<PrintStepEnum, COUNT> m_state; | ||||
| }; | ||||
| 
 | ||||
| template<typename PrintType, typename PrintObjectStepEnum, const size_t COUNT> | ||||
| 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<typename StepTypeIterator> | ||||
|     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<PrintObjectStepEnum> 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<PrintObjectStepEnum, COUNT>   m_state; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif /* slic3r_PrintBase_hpp_ */ | ||||
|  | @ -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<coord_t>(); | ||||
|     } | ||||
|      | ||||
|     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::vector<t_config_ | |||
| 
 | ||||
| bool PrintObject::invalidate_step(PrintObjectStep step) | ||||
| { | ||||
|     bool invalidated = m_state.invalidate(step, m_print->m_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<void()> PrintObject::cancel_callback() | ||||
| { | ||||
| 	return m_print->m_cancel_callback; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv