mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 20:51:12 -06:00 
			
		
		
		
	WIP: Synchronization of SLA background processing.
This commit is contained in:
		
							parent
							
								
									a21f1783a9
								
							
						
					
					
						commit
						314f7dc674
					
				
					 8 changed files with 501 additions and 114 deletions
				
			
		|  | @ -1515,6 +1515,71 @@ Transform3d ModelInstance::get_matrix(bool dont_translate, bool dont_rotate, boo | |||
| } | ||||
| #endif // !ENABLE_MODELVOLUME_TRANSFORM
 | ||||
| 
 | ||||
| // Test whether the two models contain the same number of ModelObjects with the same set of IDs
 | ||||
| // ordered in the same order. In that case it is not necessary to kill the background processing.
 | ||||
| bool model_object_list_equal(const Model &model_old, const Model &model_new) | ||||
| { | ||||
|     if (model_old.objects.size() != model_new.objects.size()) | ||||
|         return false; | ||||
|     for (size_t i = 0; i < model_old.objects.size(); ++ i) | ||||
|         if (model_old.objects[i]->id() != model_new.objects[i]->id()) | ||||
|             return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // Test whether the new model is just an extension of the old model (new objects were added
 | ||||
| // to the end of the original list. In that case it is not necessary to kill the background processing.
 | ||||
| bool model_object_list_extended(const Model &model_old, const Model &model_new) | ||||
| { | ||||
|     if (model_old.objects.size() >= model_new.objects.size()) | ||||
|         return false; | ||||
|     for (size_t i = 0; i < model_old.objects.size(); ++ i) | ||||
|         if (model_old.objects[i]->id() != model_new.objects[i]->id()) | ||||
|             return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type) | ||||
| { | ||||
|     bool modifiers_differ = false; | ||||
|     size_t i_old, i_new; | ||||
|     for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|         const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_old.type() != type) { | ||||
|             ++ i_old; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_new.type() != type) { | ||||
|             ++ i_new; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_old.id() != mv_new.id()) | ||||
|             return true; | ||||
|         //FIXME test for the content of the mesh!
 | ||||
| 
 | ||||
| #if ENABLE_MODELVOLUME_TRANSFORM | ||||
|         if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) | ||||
|             return true; | ||||
| #endif // ENABLE_MODELVOLUME_TRANSFORM
 | ||||
|         ++i_old; | ||||
|         ++ i_new; | ||||
|     } | ||||
|     for (; i_old < model_object_old.volumes.size(); ++ i_old) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|         if (mv_old.type() == type) | ||||
|             // ModelVolume was deleted.
 | ||||
|             return true; | ||||
|     } | ||||
|     for (; i_new < model_object_new.volumes.size(); ++ i_new) { | ||||
|         const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_new.type() == type) | ||||
|             // ModelVolume was added.
 | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| #ifdef _DEBUG | ||||
| // Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
 | ||||
| void check_model_ids_validity(const Model &model) | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ class ModelMaterial; | |||
| class ModelObject; | ||||
| class ModelVolume; | ||||
| class Print; | ||||
| class SLAPrint; | ||||
| 
 | ||||
| typedef std::string t_model_material_id; | ||||
| typedef std::string t_model_material_attribute; | ||||
|  | @ -252,6 +253,7 @@ public: | |||
| 
 | ||||
| protected: | ||||
|     friend class Print; | ||||
|     friend class SLAPrint; | ||||
|     // Called by Print::apply() to set the model pointer after making a copy.
 | ||||
|     void        set_model(Model *model) { m_model = model; } | ||||
| 
 | ||||
|  | @ -368,6 +370,7 @@ public: | |||
| 
 | ||||
| protected: | ||||
| 	friend class Print; | ||||
|     friend class SLAPrint; | ||||
| 	friend class ModelObject; | ||||
| 
 | ||||
| 	explicit ModelVolume(const ModelVolume &rhs) = default; | ||||
|  | @ -535,6 +538,7 @@ public: | |||
| 
 | ||||
| protected: | ||||
|     friend class Print; | ||||
|     friend class SLAPrint; | ||||
|     friend class ModelObject; | ||||
| 
 | ||||
|     explicit ModelInstance(const ModelInstance &rhs) = default; | ||||
|  | @ -652,6 +656,18 @@ private: | |||
| #undef MODELBASE_DERIVED_COPY_MOVE_CLONE | ||||
| #undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE | ||||
| 
 | ||||
| // Test whether the two models contain the same number of ModelObjects with the same set of IDs
 | ||||
| // ordered in the same order. In that case it is not necessary to kill the background processing.
 | ||||
| extern bool model_object_list_equal(const Model &model_old, const Model &model_new); | ||||
| 
 | ||||
| // Test whether the new model is just an extension of the old model (new objects were added
 | ||||
| // to the end of the original list. In that case it is not necessary to kill the background processing.
 | ||||
| extern bool model_object_list_extended(const Model &model_old, const Model &model_new); | ||||
| 
 | ||||
| // Test whether the new ModelObject contains a different set of volumes (or sorted in a different order)
 | ||||
| // than the old ModelObject.
 | ||||
| extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type); | ||||
| 
 | ||||
| #ifdef _DEBUG | ||||
| // Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
 | ||||
| void check_model_ids_validity(const Model &model); | ||||
|  |  | |||
|  | @ -550,71 +550,6 @@ exit_for_rearrange_regions: | |||
|     return invalidated; | ||||
| } | ||||
| 
 | ||||
| // Test whether the two models contain the same number of ModelObjects with the same set of IDs
 | ||||
| // ordered in the same order. In that case it is not necessary to kill the background processing.
 | ||||
| static inline bool model_object_list_equal(const Model &model_old, const Model &model_new) | ||||
| { | ||||
|     if (model_old.objects.size() != model_new.objects.size()) | ||||
|         return false; | ||||
|     for (size_t i = 0; i < model_old.objects.size(); ++ i) | ||||
|         if (model_old.objects[i]->id() != model_new.objects[i]->id()) | ||||
|             return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // Test whether the new model is just an extension of the old model (new objects were added
 | ||||
| // to the end of the original list. In that case it is not necessary to kill the background processing.
 | ||||
| static inline bool model_object_list_extended(const Model &model_old, const Model &model_new) | ||||
| { | ||||
|     if (model_old.objects.size() >= model_new.objects.size()) | ||||
|         return false; | ||||
|     for (size_t i = 0; i < model_old.objects.size(); ++ i) | ||||
|         if (model_old.objects[i]->id() != model_new.objects[i]->id()) | ||||
|             return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static inline bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type) | ||||
| { | ||||
|     bool modifiers_differ = false; | ||||
|     size_t i_old, i_new; | ||||
|     for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
| 		const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_old.type() != type) { | ||||
|             ++ i_old; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_new.type() != type) { | ||||
|             ++ i_new; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_old.id() != mv_new.id()) | ||||
|             return true; | ||||
|         //FIXME test for the content of the mesh!
 | ||||
| 
 | ||||
| #if ENABLE_MODELVOLUME_TRANSFORM | ||||
|         if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) | ||||
|             return true; | ||||
| #endif // ENABLE_MODELVOLUME_TRANSFORM
 | ||||
|         ++i_old; | ||||
|         ++ i_new; | ||||
|     } | ||||
|     for (; i_old < model_object_old.volumes.size(); ++ i_old) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|         if (mv_old.type() == type) | ||||
|             // ModelVolume was deleted.
 | ||||
|             return true; | ||||
|     } | ||||
|     for (; i_new < model_object_new.volumes.size(); ++ i_new) { | ||||
|         const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_new.type() == type) | ||||
|             // ModelVolume was added.
 | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new
 | ||||
| // in the exact order and with the same IDs.
 | ||||
| // It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order.
 | ||||
|  |  | |||
|  | @ -131,9 +131,6 @@ public: | |||
|     SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z); | ||||
|     void delete_support_layer(int idx); | ||||
|      | ||||
|     // methods for handling state
 | ||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
| 
 | ||||
|     // To be used over the layer_height_profile of both the PrintObject and ModelObject
 | ||||
|     // to initialize the height profile with the height ranges.
 | ||||
|     bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const; | ||||
|  | @ -174,6 +171,8 @@ protected: | |||
|     bool                    invalidate_step(PrintObjectStep step); | ||||
|     // Invalidates all PrintObject and Print steps.
 | ||||
|     bool                    invalidate_all_steps(); | ||||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     bool                    invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
| 
 | ||||
| private: | ||||
|     void make_perimeters(); | ||||
|  |  | |||
|  | @ -902,7 +902,7 @@ class SLAPrintObjectConfig : public StaticPrintConfig | |||
| { | ||||
|     STATIC_PRINT_CONFIG_CACHE(SLAPrintObjectConfig) | ||||
| public: | ||||
|     ConfigOptionFloat                       layer_height; | ||||
|     ConfigOptionFloat layer_height; | ||||
| 
 | ||||
|     // Radius in mm of the pointing side of the head.
 | ||||
|     ConfigOptionFloat support_head_front_radius /*= 0.2*/; | ||||
|  |  | |||
|  | @ -73,53 +73,296 @@ void SLAPrint::clear() | |||
| 	m_objects.clear(); | ||||
| } | ||||
| 
 | ||||
| // Transformation without rotation around Z and without a shift by X and Y.
 | ||||
| static Transform3d sla_trafo(const ModelObject &model_object) | ||||
| { | ||||
|     ModelInstance &model_instance = *model_object.instances.front(); | ||||
|     Vec3d          offset         = model_instance.get_offset(); | ||||
|     Vec3d          rotation       = model_instance.get_rotation(); | ||||
|     offset(0) = 0.; | ||||
|     offset(1) = 0.; | ||||
|     rotation(2) = 0.; | ||||
|     return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); | ||||
| } | ||||
| 
 | ||||
| // List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance.
 | ||||
| static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object) | ||||
| { | ||||
|     std::vector<SLAPrintObject::Instance> instances; | ||||
|     for (ModelInstance *model_instance : model_object.instances) | ||||
|         if (model_instance->is_printable()) { | ||||
|             instances.emplace_back(SLAPrintObject::Instance( | ||||
|                 model_instance->id(),  | ||||
|                 Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), | ||||
|                 float(model_instance->get_rotation(Z)))); | ||||
|         } | ||||
|     return instances; | ||||
| } | ||||
| 
 | ||||
| SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, | ||||
|                                       const DynamicPrintConfig &config_in) | ||||
| { | ||||
| //	if (m_objects.empty())
 | ||||
| //		return APPLY_STATUS_UNCHANGED;
 | ||||
| #ifdef _DEBUG | ||||
|     check_model_ids_validity(model); | ||||
| #endif /* _DEBUG */ | ||||
| 
 | ||||
|     // Make a copy of the config, normalize it.
 | ||||
|     DynamicPrintConfig config(config_in); | ||||
|     config.normalize(); | ||||
|     // Collect changes to print config.
 | ||||
|     t_config_option_keys printer_diff  = m_printer_config.diff(config); | ||||
|     t_config_option_keys material_diff = m_material_config.diff(config); | ||||
|     t_config_option_keys object_diff   = m_default_object_config.diff(config); | ||||
| 
 | ||||
|     // Do not use the ApplyStatus as we will use the max function when updating apply_status. 
 | ||||
|     unsigned int apply_status = APPLY_STATUS_UNCHANGED; | ||||
|     auto update_apply_status = [&apply_status](bool invalidated) | ||||
|         { apply_status = std::max<unsigned int>(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); }; | ||||
|     if (! (printer_diff.empty() && material_diff.empty() && object_diff.empty())) | ||||
|         update_apply_status(false); | ||||
| 
 | ||||
|     // Grab the lock for the Print / PrintObject milestones.
 | ||||
| 	tbb::mutex::scoped_lock lock(this->state_mutex()); | ||||
| 	if (m_objects.empty() && model.objects.empty() && m_model.objects.empty()) | ||||
|         return APPLY_STATUS_UNCHANGED; | ||||
| 
 | ||||
|     // Temporary: just to have to correct layer height for the rasterization
 | ||||
|     DynamicPrintConfig config(config_in); | ||||
|     config.normalize(); | ||||
|     m_material_config.initial_layer_height.set( | ||||
|                 config.opt<ConfigOptionFloat>("initial_layer_height")); | ||||
|     // The following call may stop the background processing.
 | ||||
|     update_apply_status(this->invalidate_state_by_config_options(printer_diff)); | ||||
|     update_apply_status(this->invalidate_state_by_config_options(material_diff)); | ||||
| 
 | ||||
| 	// Temporary quick fix, just invalidate everything.
 | ||||
|     { | ||||
|         for (SLAPrintObject *print_object : m_objects) { | ||||
| 			print_object->invalidate_all_steps(); | ||||
|             delete print_object; | ||||
| 		} | ||||
| 		m_objects.clear(); | ||||
| 		this->invalidate_all_steps(); | ||||
|     // It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
 | ||||
| 	m_printer_config.apply_only(config, printer_diff, true); | ||||
|     // Handle changes to material config.
 | ||||
|     m_material_config.apply_only(config, material_diff, true); | ||||
|     // Handle changes to object config defaults
 | ||||
|     m_default_object_config.apply_only(config, object_diff, true); | ||||
| 
 | ||||
|         // Copy the model by value (deep copy),
 | ||||
|         // keep the Model / ModelObject / ModelInstance / ModelVolume IDs.
 | ||||
|     struct ModelObjectStatus { | ||||
|         enum Status { | ||||
|             Unknown, | ||||
|             Old, | ||||
|             New, | ||||
|             Moved, | ||||
|             Deleted, | ||||
|         }; | ||||
|         ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {} | ||||
|         ModelID                 id; | ||||
|         Status                  status; | ||||
|         // Search by id.
 | ||||
|         bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; } | ||||
|     }; | ||||
|     std::set<ModelObjectStatus> model_object_status; | ||||
| 
 | ||||
|     // 1) Synchronize model objects.
 | ||||
|     if (model.id() != m_model.id()) { | ||||
|         // Kill everything, initialize from scratch.
 | ||||
|         // Stop background processing.
 | ||||
|         this->call_cancell_callback(); | ||||
|         update_apply_status(this->invalidate_all_steps()); | ||||
|         for (SLAPrintObject *object : m_objects) { | ||||
|             model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); | ||||
|             delete object; | ||||
|         } | ||||
|         m_objects.clear(); | ||||
|         m_model.assign_copy(model); | ||||
|         // Generate new SLAPrintObjects.
 | ||||
|         for (ModelObject *model_object : m_model.objects) { | ||||
|             auto po = new SLAPrintObject(this, model_object); | ||||
| 
 | ||||
|             // po->m_config.layer_height.set(lh);
 | ||||
|             po->m_config.apply(config, true); | ||||
| 
 | ||||
|             m_objects.emplace_back(po); | ||||
|             for (ModelInstance *oinst : model_object->instances) { | ||||
|                 Point tr = Point::new_scale(oinst->get_offset()(X), | ||||
|                                             oinst->get_offset()(Y)); | ||||
|                 auto rotZ = float(oinst->get_rotation()(Z)); | ||||
| 				po->m_instances.emplace_back(oinst->id(), tr, rotZ); | ||||
|         for (const ModelObject *model_object : m_model.objects) | ||||
|             model_object_status.emplace(model_object->id(), ModelObjectStatus::New); | ||||
|     } else { | ||||
|         if (model_object_list_equal(m_model, model)) { | ||||
|             // The object list did not change.
 | ||||
|             for (const ModelObject *model_object : m_model.objects) | ||||
|                 model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); | ||||
|         } else if (model_object_list_extended(m_model, model)) { | ||||
|             // Add new objects. Their volumes and configs will be synchronized later.
 | ||||
|             update_apply_status(this->invalidate_step(slapsRasterize)); | ||||
|             for (const ModelObject *model_object : m_model.objects) | ||||
|                 model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); | ||||
|             for (size_t i = m_model.objects.size(); i < model.objects.size(); ++ i) { | ||||
|                 model_object_status.emplace(model.objects[i]->id(), ModelObjectStatus::New); | ||||
|                 m_model.objects.emplace_back(ModelObject::new_copy(*model.objects[i])); | ||||
|                 m_model.objects.back()->set_model(&m_model); | ||||
|             } | ||||
|         } else { | ||||
|             // Reorder the objects, add new objects.
 | ||||
|             // First stop background processing before shuffling or deleting the PrintObjects in the object list.
 | ||||
|             this->call_cancell_callback(); | ||||
|             update_apply_status(this->invalidate_step(slapsRasterize)); | ||||
|             // Second create a new list of objects.
 | ||||
|             std::vector<ModelObject*> model_objects_old(std::move(m_model.objects)); | ||||
|             m_model.objects.clear(); | ||||
|             m_model.objects.reserve(model.objects.size()); | ||||
|             auto by_id_lower = [](const ModelObject *lhs, const ModelObject *rhs){ return lhs->id() < rhs->id(); }; | ||||
|             std::sort(model_objects_old.begin(), model_objects_old.end(), by_id_lower); | ||||
|             for (const ModelObject *mobj : model.objects) { | ||||
|                 auto it = std::lower_bound(model_objects_old.begin(), model_objects_old.end(), mobj, by_id_lower); | ||||
|                 if (it == model_objects_old.end() || (*it)->id() != mobj->id()) { | ||||
|                     // New ModelObject added.
 | ||||
|                     m_model.objects.emplace_back(ModelObject::new_copy(*mobj)); | ||||
|                     m_model.objects.back()->set_model(&m_model); | ||||
|                     model_object_status.emplace(mobj->id(), ModelObjectStatus::New); | ||||
|                 } else { | ||||
|                     // Existing ModelObject re-added (possibly moved in the list).
 | ||||
|                     m_model.objects.emplace_back(*it); | ||||
|                     model_object_status.emplace(mobj->id(), ModelObjectStatus::Moved); | ||||
|                 } | ||||
|             } | ||||
|             bool deleted_any = false; | ||||
|             for (ModelObject *&model_object : model_objects_old) { | ||||
|                 if (model_object_status.find(ModelObjectStatus(model_object->id())) == model_object_status.end()) { | ||||
|                     model_object_status.emplace(model_object->id(), ModelObjectStatus::Deleted); | ||||
|                     deleted_any = true; | ||||
|                 } else | ||||
|                     // Do not delete this ModelObject instance.
 | ||||
|                     model_object = nullptr; | ||||
|             } | ||||
|             if (deleted_any) { | ||||
|                 // Delete PrintObjects of the deleted ModelObjects.
 | ||||
|                 std::vector<SLAPrintObject*> print_objects_old = std::move(m_objects); | ||||
|                 m_objects.clear(); | ||||
|                 m_objects.reserve(print_objects_old.size()); | ||||
|                 for (SLAPrintObject *print_object : print_objects_old) { | ||||
|                     auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id())); | ||||
|                     assert(it_status != model_object_status.end()); | ||||
|                     if (it_status->status == ModelObjectStatus::Deleted) { | ||||
|                         update_apply_status(print_object->invalidate_all_steps()); | ||||
|                         delete print_object; | ||||
|                     } else | ||||
|                         m_objects.emplace_back(print_object); | ||||
|                 } | ||||
|                 for (ModelObject *model_object : model_objects_old) | ||||
|                     delete model_object; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	return APPLY_STATUS_INVALIDATED; | ||||
|     // 2) Map print objects including their transformation matrices.
 | ||||
|     struct PrintObjectStatus { | ||||
|         enum Status { | ||||
|             Unknown, | ||||
|             Deleted, | ||||
|             Reused, | ||||
|             New | ||||
|         }; | ||||
|         PrintObjectStatus(SLAPrintObject *print_object, Status status = Unknown) :  | ||||
|             id(print_object->model_object()->id()), | ||||
|             print_object(print_object), | ||||
|             trafo(print_object->trafo()), | ||||
|             status(status) {} | ||||
|         PrintObjectStatus(ModelID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {} | ||||
|         // ID of the ModelObject & PrintObject
 | ||||
|         ModelID          id; | ||||
|         // Pointer to the old PrintObject
 | ||||
|         SLAPrintObject  *print_object; | ||||
|         // Trafo generated with model_object->world_matrix(true) 
 | ||||
|         Transform3d      trafo; | ||||
|         Status           status; | ||||
|         // Search by id.
 | ||||
|         bool operator<(const PrintObjectStatus &rhs) const { return id < rhs.id; } | ||||
|     }; | ||||
|     std::multiset<PrintObjectStatus> print_object_status; | ||||
|     for (SLAPrintObject *print_object : m_objects) | ||||
|         print_object_status.emplace(PrintObjectStatus(print_object)); | ||||
| 
 | ||||
|     // 3) Synchronize ModelObjects & PrintObjects.
 | ||||
|     std::vector<SLAPrintObject*> print_objects_new; | ||||
|     print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size())); | ||||
|     bool new_objects = false; | ||||
|     for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) { | ||||
|         ModelObject &model_object = *m_model.objects[idx_model_object]; | ||||
|         auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); | ||||
|         assert(it_status != model_object_status.end()); | ||||
|         assert(it_status->status != ModelObjectStatus::Deleted); | ||||
|         if (it_status->status == ModelObjectStatus::New) | ||||
|             // PrintObject instances will be added in the next loop.
 | ||||
|             continue; | ||||
|         // Update the ModelObject instance, possibly invalidate the linked PrintObjects.
 | ||||
|         assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); | ||||
|         const ModelObject &model_object_new       = *model.objects[idx_model_object]; | ||||
|         auto               it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id())); | ||||
| 		if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id()) | ||||
|             it_print_object_status = print_object_status.end(); | ||||
|         // Check whether a model part volume was added or removed, their transformations or order changed.
 | ||||
|         bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART); | ||||
|         bool sla_trafo_differs  = model_object.instances.empty() != model_object_new.instances.empty() ||  | ||||
|             (! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new))); | ||||
|         if (model_parts_differ || sla_trafo_differs) { | ||||
|             // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
 | ||||
| 			if (it_print_object_status != print_object_status.end()) { | ||||
| 				update_apply_status(it_print_object_status->print_object->invalidate_all_steps()); | ||||
| 				const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted; | ||||
|             } | ||||
|             // Copy content of the ModelObject including its ID, do not change the parent.
 | ||||
|             model_object.assign_copy(model_object_new); | ||||
|         } else { | ||||
|             // Synchronize Object's config.
 | ||||
|             bool object_config_changed = model_object.config != model_object_new.config; | ||||
|             if (object_config_changed) | ||||
|                 model_object.config = model_object_new.config; | ||||
|             if (! object_diff.empty() || object_config_changed) { | ||||
|                 SLAPrintObjectConfig new_config = m_default_object_config; | ||||
|                 normalize_and_apply_config(new_config, model_object.config); | ||||
|                 if (it_print_object_status != print_object_status.end()) { | ||||
| 					t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config); | ||||
|                     if (! diff.empty()) { | ||||
|                         update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff)); | ||||
|                         it_print_object_status->print_object->config_apply_only(new_config, diff, true); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (model_object.sla_support_points != model_object_new.sla_support_points) { | ||||
|                 model_object.sla_support_points = model_object_new.sla_support_points; | ||||
|                 if (it_print_object_status != print_object_status.end()) | ||||
|                     update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
|             } | ||||
|             // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
 | ||||
|             model_object.name       = model_object_new.name; | ||||
|             model_object.input_file = model_object_new.input_file; | ||||
|             model_object.clear_instances(); | ||||
|             model_object.instances.reserve(model_object_new.instances.size()); | ||||
|             for (const ModelInstance *model_instance : model_object_new.instances) { | ||||
|                 model_object.instances.emplace_back(new ModelInstance(*model_instance)); | ||||
|                 model_object.instances.back()->set_model_object(&model_object); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         std::vector<SLAPrintObject::Instance> new_instances = sla_instances(model_object); | ||||
|         if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) { | ||||
|             // The SLAPrintObject is already there.
 | ||||
|             if (new_instances != it_print_object_status->print_object->instances()) { | ||||
|                 // Instances changed.
 | ||||
|                 it_print_object_status->print_object->set_instances(new_instances); | ||||
|                 update_apply_status(this->invalidate_step(slapsRasterize)); | ||||
|             } | ||||
|             print_objects_new.emplace_back(it_print_object_status->print_object); | ||||
|             const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused; | ||||
|         } else { | ||||
|             auto print_object = new SLAPrintObject(this, &model_object); | ||||
|             print_object->set_trafo(sla_trafo(model_object)); | ||||
|             print_object->set_instances(new_instances); | ||||
|             print_object->config_apply(config, true); | ||||
|             print_objects_new.emplace_back(print_object); | ||||
|             new_objects = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (m_objects != print_objects_new) { | ||||
|         this->call_cancell_callback(); | ||||
|         update_apply_status(this->invalidate_all_steps()); | ||||
|         m_objects = print_objects_new; | ||||
|         // Delete the PrintObjects marked as Unknown or Deleted.
 | ||||
|         bool deleted_objects = false; | ||||
|         for (auto &pos : print_object_status) | ||||
|             if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) { | ||||
|                 // update_apply_status(pos.print_object->invalidate_all_steps());
 | ||||
|                 delete pos.print_object; | ||||
|                 deleted_objects = true; | ||||
|             } | ||||
|         update_apply_status(new_objects); | ||||
|     } | ||||
| 
 | ||||
| #ifdef _DEBUG | ||||
|     check_model_ids_equal(m_model, model); | ||||
| #endif /* _DEBUG */ | ||||
| 
 | ||||
|     return static_cast<ApplyStatus>(apply_status); | ||||
| } | ||||
| 
 | ||||
| void SLAPrint::process() | ||||
|  | @ -498,6 +741,61 @@ void SLAPrint::process() | |||
|     set_status(100, L("Slicing done")); | ||||
| } | ||||
| 
 | ||||
| bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys) | ||||
| { | ||||
|     if (opt_keys.empty()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Cache the plenty of parameters, which influence the final rasterization only,
 | ||||
|     // or they are only notes not influencing the rasterization step.
 | ||||
|     static std::unordered_set<std::string> steps_rasterize = { | ||||
|         "exposure_time", | ||||
|         "initial_exposure_time", | ||||
|         "material_correction_printing", | ||||
|         "material_correction_curing", | ||||
|         "display_width", | ||||
|         "display_height", | ||||
|         "display_pixels_x", | ||||
|         "display_pixels_y", | ||||
|         "printer_correction" | ||||
|     }; | ||||
| 
 | ||||
|     static std::unordered_set<std::string> steps_ignore = { | ||||
|         "bed_shape", | ||||
|         "max_print_height", | ||||
|         "printer_technology", | ||||
|     }; | ||||
| 
 | ||||
|     std::vector<SLAPrintStep> steps; | ||||
|     std::vector<SLAPrintObjectStep> osteps; | ||||
|     bool invalidated = false; | ||||
| 
 | ||||
|     for (const t_config_option_key &opt_key : opt_keys) { | ||||
|         if (steps_rasterize.find(opt_key) != steps_rasterize.end()) { | ||||
|             // These options only affect the final rasterization, or they are just notes without influence on the output,
 | ||||
|             // so there is nothing to invalidate.
 | ||||
|             steps.emplace_back(slapsRasterize); | ||||
|         } else if (steps_ignore.find(opt_key) != steps_ignore.end()) { | ||||
|             // These steps have no influence on the output. Just ignore them.
 | ||||
|         } else if (opt_key == "initial_layer_height") { | ||||
|             steps.emplace_back(slapsRasterize); | ||||
|             osteps.emplace_back(slaposObjectSlice); | ||||
|         } else { | ||||
|             // All values should be covered.
 | ||||
|             assert(false); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     sort_remove_duplicates(steps); | ||||
|     for (SLAPrintStep step : steps) | ||||
|         invalidated |= this->invalidate_step(step); | ||||
|     sort_remove_duplicates(osteps); | ||||
|     for (SLAPrintObjectStep ostep : osteps) | ||||
|         for (SLAPrintObject *object : m_objects) | ||||
|             invalidated |= object->invalidate_step(ostep); | ||||
|     return invalidated; | ||||
| } | ||||
| 
 | ||||
| SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): | ||||
|     Inherited(print, model_object), | ||||
|     m_stepmask(slaposCount, true) | ||||
|  | @ -506,6 +804,75 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): | |||
| 
 | ||||
| SLAPrintObject::~SLAPrintObject() {} | ||||
| 
 | ||||
| // Called by SLAPrint::apply_config().
 | ||||
| // This method only accepts SLAPrintObjectConfig option keys.
 | ||||
| bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys) | ||||
| { | ||||
|     if (opt_keys.empty()) | ||||
|         return false; | ||||
| 
 | ||||
|     std::vector<SLAPrintObjectStep> steps; | ||||
|     bool invalidated = false; | ||||
|     for (const t_config_option_key &opt_key : opt_keys) { | ||||
|         if (   opt_key == "support_head_front_radius" | ||||
|             || opt_key == "support_head_penetration" | ||||
|             || opt_key == "support_head_back_radius" | ||||
|             || opt_key == "support_head_width" | ||||
|             || opt_key == "support_pillar_radius" | ||||
|             || opt_key == "support_base_radius" | ||||
|             || opt_key == "support_base_height" | ||||
|             || opt_key == "support_critical_angle" | ||||
|             || opt_key == "support_max_bridge_length" | ||||
|             || opt_key == "support_object_elevation") { | ||||
|             steps.emplace_back(slaposSupportTree); | ||||
|         } else if ( | ||||
|                opt_key == "pad_enable" | ||||
|             || opt_key == "pad_wall_thickness" | ||||
|             || opt_key == "pad_wall_height" | ||||
|             || opt_key == "pad_max_merge_distance" | ||||
|             || opt_key == "pad_edge_radius") { | ||||
|             steps.emplace_back(slaposBasePool); | ||||
|         } else { | ||||
|             // All keys should be covered.
 | ||||
|             assert(false); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     sort_remove_duplicates(steps); | ||||
|     for (SLAPrintObjectStep step : steps) | ||||
|         invalidated |= this->invalidate_step(step); | ||||
|     return invalidated; | ||||
| } | ||||
| 
 | ||||
| bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step) | ||||
| { | ||||
|     bool invalidated = Inherited::invalidate_step(step); | ||||
|     // propagate to dependent steps
 | ||||
|     if (step == slaposObjectSlice) { | ||||
|         invalidated |= this->invalidate_all_steps(); | ||||
|     } else if (step == slaposSupportIslands) { | ||||
|         invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposBasePool, slaposSliceSupports }); | ||||
|         invalidated |= m_print->invalidate_step(slapsRasterize); | ||||
|     } else if (step == slaposSupportPoints) { | ||||
|         invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports }); | ||||
|         invalidated |= m_print->invalidate_step(slapsRasterize); | ||||
|     } else if (step == slaposSupportTree) { | ||||
|         invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports }); | ||||
|         invalidated |= m_print->invalidate_step(slapsRasterize); | ||||
|     } else if (step == slaposBasePool) { | ||||
|         invalidated |= this->invalidate_step(slaposSliceSupports); | ||||
|         invalidated |= m_print->invalidate_step(slapsRasterize); | ||||
|     } else if (step == slaposSliceSupports) { | ||||
|         invalidated |= m_print->invalidate_step(slapsRasterize); | ||||
|     } | ||||
|     return invalidated; | ||||
| } | ||||
| 
 | ||||
| bool SLAPrintObject::invalidate_all_steps() | ||||
| { | ||||
|     return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps(); | ||||
| } | ||||
| 
 | ||||
| double SLAPrintObject::get_elevation() const { | ||||
|     double ret = m_config.support_object_elevation.getFloat(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,16 +35,18 @@ private: // Prevents erroneous use by other classes. | |||
|     using Inherited = _SLAPrintObjectBase; | ||||
| 
 | ||||
| public: | ||||
|     const Transform3d&      trafo()        const    { return m_trafo; } | ||||
|     const SLAPrintObjectConfig& config() const { return m_config; } | ||||
|     const Transform3d&          trafo()  const { return m_trafo; } | ||||
| 
 | ||||
|     struct Instance { | ||||
|     	Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {} | ||||
| 		bool operator==(const Instance &rhs) const { return this->instance_id == rhs.instance_id && this->shift == rhs.shift && this->rotation == rhs.rotation; } | ||||
|     	// ID of the corresponding ModelInstance.
 | ||||
| 		ModelID instance_id; | ||||
| 		// Slic3r::Point objects in scaled G-code coordinates
 | ||||
|     	Point 	shift; | ||||
|     	// Rotation along the Z axis, in radians.
 | ||||
|     	float 	rotation;  | ||||
|     	float 	rotation; | ||||
| 	}; | ||||
|     const std::vector<Instance>& instances() const { return m_instances; } | ||||
| 
 | ||||
|  | @ -88,12 +90,14 @@ protected: | |||
|     	{ this->m_config.apply_only(other, keys, ignore_nonexistent); } | ||||
|     void                    set_trafo(const Transform3d& trafo) { m_trafo = trafo; m_trmesh_valid = false; } | ||||
| 
 | ||||
|     bool                    set_instances(const std::vector<Instance> &instances); | ||||
|     void                    set_instances(const std::vector<Instance> &instances) { m_instances = instances; } | ||||
|     // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
 | ||||
|     bool                    invalidate_step(SLAPrintObjectStep step); | ||||
|     bool                    invalidate_all_steps(); | ||||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     bool                    invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|     // Object specific configuration, pulled from the configuration layer.
 | ||||
|     SLAPrintObjectConfig                    m_config; | ||||
|     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
 | ||||
|  | @ -150,8 +154,13 @@ private: | |||
|     using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; | ||||
|     using SLAPrinterPtr = std::unique_ptr<SLAPrinter>; | ||||
| 
 | ||||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
| 
 | ||||
|     SLAPrinterConfig                m_printer_config; | ||||
|     SLAMaterialConfig               m_material_config; | ||||
|     SLAPrintObjectConfig            m_default_object_config; | ||||
| 
 | ||||
|     PrintObjects                    m_objects; | ||||
|     std::vector<bool>               m_stepmask; | ||||
|     SLAPrinterPtr                   m_printer; | ||||
|  |  | |||
|  | @ -822,16 +822,13 @@ void GLVolumeCollection::load_object_auxiliary( | |||
|     bool                            use_VBOs) | ||||
| { | ||||
|     assert(print_object->is_step_done(milestone)); | ||||
|     Transform3d  mesh_trafo_inv = print_object->trafo().inverse(); | ||||
|     // Get the support mesh.
 | ||||
|     TriangleMesh mesh; | ||||
|     switch (milestone) { | ||||
|     case slaposSupportTree: mesh = print_object->support_mesh(); break; | ||||
|     case slaposBasePool:    mesh = print_object->pad_mesh();     break; | ||||
|     default: | ||||
|         assert(false); | ||||
|     } | ||||
|     TriangleMesh mesh = print_object->get_mesh(milestone); | ||||
|     mesh.transform(mesh_trafo_inv); | ||||
| 	// Convex hull is required for out of print bed detection.
 | ||||
| 	TriangleMesh convex_hull = mesh.convex_hull_3d(); | ||||
|     convex_hull.transform(mesh_trafo_inv); | ||||
|     for (const std::pair<size_t, size_t> &instance_idx : instances) { | ||||
|         const ModelInstance            &model_instance = *print_object->model_object()->instances[instance_idx.first]; | ||||
|         const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second]; | ||||
|  | @ -851,7 +848,6 @@ void GLVolumeCollection::load_object_auxiliary( | |||
| 		v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true); | ||||
|         v.is_modifier  = false; | ||||
|         v.shader_outside_printer_detection_enabled = true; | ||||
|         //FIXME adjust with print_instance?
 | ||||
| 		v.set_instance_transformation(model_instance.get_transformation()); | ||||
| 		// Leave the volume transformation at identity.
 | ||||
|         // v.set_volume_transformation(model_volume->get_transformation());
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv