mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-20 07:11:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'remotes/origin/vb_modelobject'
This commit is contained in:
		
						commit
						ab0890ed34
					
				
					 34 changed files with 444 additions and 260 deletions
				
			
		|  | @ -93,7 +93,7 @@ int CLI::run(int argc, char **argv) | |||
| 		return 1; | ||||
| 
 | ||||
|     m_extra_config.apply(m_config, true); | ||||
|     m_extra_config.normalize(); | ||||
|     m_extra_config.normalize_fdm(); | ||||
|      | ||||
|     PrinterTechnology printer_technology = Slic3r::printer_technology(m_config); | ||||
| 
 | ||||
|  | @ -129,7 +129,7 @@ int CLI::run(int argc, char **argv) | |||
|             boost::nowide::cerr << "Error while reading config file: " << ex.what() << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|         config.normalize(); | ||||
|         config.normalize_fdm(); | ||||
|         PrinterTechnology other_printer_technology = Slic3r::printer_technology(config); | ||||
|         if (printer_technology == ptUnknown) { | ||||
|             printer_technology = other_printer_technology; | ||||
|  | @ -196,7 +196,7 @@ int CLI::run(int argc, char **argv) | |||
|     // (command line options override --load files)
 | ||||
|     m_print_config.apply(m_extra_config, true); | ||||
|     // Normalizing after importing the 3MFs / AMFs
 | ||||
|     m_print_config.normalize(); | ||||
|     m_print_config.normalize_fdm(); | ||||
| 
 | ||||
|     // Initialize full print configs for both the FFF and SLA technologies.
 | ||||
|     FullPrintConfig    fff_print_config; | ||||
|  |  | |||
|  | @ -683,23 +683,23 @@ namespace Slic3r { | |||
|             // m_layer_heights_profiles are indexed by a 1 based model object index.
 | ||||
|             IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1); | ||||
|             if (obj_layer_heights_profile != m_layer_heights_profiles.end()) | ||||
|                 model_object->layer_height_profile = obj_layer_heights_profile->second; | ||||
|                 model_object->layer_height_profile.set(std::move(obj_layer_heights_profile->second)); | ||||
| 
 | ||||
|             // m_layer_config_ranges are indexed by a 1 based model object index.
 | ||||
|             IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1); | ||||
|             if (obj_layer_config_ranges != m_layer_config_ranges.end()) | ||||
|                 model_object->layer_config_ranges = obj_layer_config_ranges->second; | ||||
|                 model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second); | ||||
| 
 | ||||
|             // m_sla_support_points are indexed by a 1 based model object index.
 | ||||
|             IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1); | ||||
|             if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) { | ||||
|                 model_object->sla_support_points = obj_sla_support_points->second; | ||||
|                 model_object->sla_support_points = std::move(obj_sla_support_points->second); | ||||
|                 model_object->sla_points_status = sla::PointsStatus::UserModified; | ||||
|             } | ||||
|              | ||||
|             IdToSlaDrainHolesMap::iterator obj_drain_holes = m_sla_drain_holes.find(object.second + 1); | ||||
|             if (obj_drain_holes != m_sla_drain_holes.end() && !obj_drain_holes->second.empty()) { | ||||
|                 model_object->sla_drain_holes = obj_drain_holes->second; | ||||
|                 model_object->sla_drain_holes = std::move(obj_drain_holes->second); | ||||
|             } | ||||
| 
 | ||||
|             IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first); | ||||
|  | @ -934,7 +934,7 @@ namespace Slic3r { | |||
|                     double max_z = range_tree.get<double>("<xmlattr>.max_z"); | ||||
| 
 | ||||
|                     // get Z range information
 | ||||
|                     DynamicPrintConfig& config = config_ranges[{ min_z, max_z }]; | ||||
|                     DynamicPrintConfig config; | ||||
| 
 | ||||
|                     for (const auto& option : range_tree) | ||||
|                     { | ||||
|  | @ -945,10 +945,12 @@ namespace Slic3r { | |||
| 
 | ||||
|                         config.set_deserialize(opt_key, value); | ||||
|                     } | ||||
| 
 | ||||
|                     config_ranges[{ min_z, max_z }].assign_config(std::move(config)); | ||||
|                 } | ||||
| 
 | ||||
|                 if (!config_ranges.empty()) | ||||
|                     m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(obj_idx, config_ranges)); | ||||
|                     m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(obj_idx, std::move(config_ranges))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -2407,7 +2409,7 @@ namespace Slic3r { | |||
|             triangles_count += (int)its.indices.size(); | ||||
|             volume_it->second.last_triangle_id = triangles_count - 1; | ||||
| 
 | ||||
|             for (size_t i = 0; i < its.indices.size(); ++ i) | ||||
|             for (int i = 0; i < int(its.indices.size()); ++ i) | ||||
|             { | ||||
|                 stream << "     <" << TRIANGLE_TAG << " "; | ||||
|                 for (int j = 0; j < 3; ++j) | ||||
|  | @ -2472,7 +2474,7 @@ namespace Slic3r { | |||
|         for (const ModelObject* object : model.objects) | ||||
|         { | ||||
|             ++count; | ||||
|             const std::vector<double> &layer_height_profile = object->layer_height_profile; | ||||
|             const std::vector<double>& layer_height_profile = object->layer_height_profile.get(); | ||||
|             if ((layer_height_profile.size() >= 4) && ((layer_height_profile.size() % 2) == 0)) | ||||
|             { | ||||
|                 sprintf(buffer, "object_id=%d|", count); | ||||
|  | @ -2527,7 +2529,7 @@ namespace Slic3r { | |||
|                     range_tree.put("<xmlattr>.max_z", range.first.second); | ||||
| 
 | ||||
|                     // store range configuration
 | ||||
|                     const DynamicPrintConfig& config = range.second; | ||||
|                     const ModelConfig& config = range.second; | ||||
|                     for (const std::string& opt_key : config.keys()) | ||||
|                     { | ||||
|                         pt::ptree& opt_tree = range_tree.add("option", config.opt_serialize(opt_key)); | ||||
|  |  | |||
|  | @ -688,7 +688,7 @@ void AMFParserContext::endElement(const char * /* name */) | |||
|         else if (strncmp(m_value[0].c_str(), "slic3r.", 7) == 0) { | ||||
|             const char *opt_key = m_value[0].c_str() + 7; | ||||
|             if (print_config_def.options.find(opt_key) != print_config_def.options.end()) { | ||||
|                 DynamicPrintConfig *config = nullptr; | ||||
|                 ModelConfig *config = nullptr; | ||||
|                 if (m_path.size() == 3) { | ||||
|                     if (m_path[1] == NODE_TYPE_MATERIAL && m_material) | ||||
|                         config = &m_material->config; | ||||
|  | @ -706,15 +706,17 @@ void AMFParserContext::endElement(const char * /* name */) | |||
|             } else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) { | ||||
|                 // Parse object's layer height profile, a semicolon separated list of floats.
 | ||||
|                 char *p = m_value[1].data(); | ||||
|                 std::vector<coordf_t> data; | ||||
|                 for (;;) { | ||||
|                     char *end = strchr(p, ';'); | ||||
|                     if (end != nullptr) | ||||
| 	                    *end = 0; | ||||
|                     m_object->layer_height_profile.push_back(float(atof(p))); | ||||
|                     data.emplace_back(float(atof(p))); | ||||
| 					if (end == nullptr) | ||||
| 						break; | ||||
| 					p = end + 1; | ||||
|                 } | ||||
|                 m_object->layer_height_profile.set(std::move(data)); | ||||
|             } | ||||
|             else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) { | ||||
|                 // Parse object's layer height profile, a semicolon separated list of floats.
 | ||||
|  | @ -1095,7 +1097,7 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, | |||
|             stream << "    <metadata type=\"slic3r." << key << "\">" << object->config.opt_serialize(key) << "</metadata>\n"; | ||||
|         if (!object->name.empty()) | ||||
|             stream << "    <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n"; | ||||
|         const std::vector<double> &layer_height_profile = object->layer_height_profile; | ||||
|         const std::vector<double> &layer_height_profile = object->layer_height_profile.get(); | ||||
|         if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) { | ||||
|             // Store the layer height profile as a single semicolon separated list.
 | ||||
|             stream << "    <metadata type=\"slic3r.layer_height_profile\">"; | ||||
|  | @ -1112,7 +1114,7 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, | |||
|             // Store the layer config range as a single semicolon separated list.
 | ||||
|             stream << "    <layer_config_ranges>\n"; | ||||
|             size_t layer_counter = 0; | ||||
|             for (auto range : config_ranges) { | ||||
|             for (const auto &range : config_ranges) { | ||||
|                 stream << "      <range id=\"" << layer_counter << "\">\n"; | ||||
| 
 | ||||
|                 stream << "        <metadata type=\"slic3r.layer_height_range\">"; | ||||
|  |  | |||
|  | @ -1050,7 +1050,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial | |||
|             ModelVolume* vol = new_object->add_volume(mesh); | ||||
|             vol->name = volume->name; | ||||
|             // Don't copy the config's ID.
 | ||||
|             static_cast<DynamicPrintConfig&>(vol->config) = static_cast<const DynamicPrintConfig&>(volume->config); | ||||
|             vol->config.assign_config(volume->config); | ||||
|             assert(vol->config.id().valid()); | ||||
|             assert(vol->config.id() != volume->config.id()); | ||||
|             vol->set_material(volume->material_id(), *volume->material()); | ||||
|  | @ -1193,7 +1193,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b | |||
|                 ModelVolume* vol = upper->add_volume(upper_mesh); | ||||
|                 vol->name	= volume->name; | ||||
|                 // Don't copy the config's ID.
 | ||||
| 				static_cast<DynamicPrintConfig&>(vol->config) = static_cast<const DynamicPrintConfig&>(volume->config); | ||||
|                 vol->config.assign_config(volume->config); | ||||
|     			assert(vol->config.id().valid()); | ||||
| 	    		assert(vol->config.id() != volume->config.id()); | ||||
|                 vol->set_material(volume->material_id(), *volume->material()); | ||||
|  | @ -1202,7 +1202,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b | |||
|                 ModelVolume* vol = lower->add_volume(lower_mesh); | ||||
|                 vol->name	= volume->name; | ||||
|                 // Don't copy the config's ID.
 | ||||
| 				static_cast<DynamicPrintConfig&>(vol->config) = static_cast<const DynamicPrintConfig&>(volume->config); | ||||
|                 vol->config.assign_config(volume->config); | ||||
|                 assert(vol->config.id().valid()); | ||||
| 	    		assert(vol->config.id() != volume->config.id()); | ||||
|                 vol->set_material(volume->material_id(), *volume->material()); | ||||
|  | @ -1280,7 +1280,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects) | |||
|         ModelObject* new_object = m_model->add_object();     | ||||
|         new_object->name   = this->name; | ||||
|         // Don't copy the config's ID.
 | ||||
| 		static_cast<DynamicPrintConfig&>(new_object->config) = static_cast<const DynamicPrintConfig&>(this->config); | ||||
| 		new_object->config.assign_config(this->config); | ||||
| 		assert(new_object->config.id().valid()); | ||||
| 		assert(new_object->config.id() != this->config.id()); | ||||
|         new_object->instances.reserve(this->instances.size()); | ||||
|  | @ -1867,7 +1867,6 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const | ||||
| { | ||||
|     TriangleSelector selector(mv.mesh()); | ||||
|  | @ -1876,29 +1875,23 @@ indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, Enforce | |||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| bool FacetsAnnotation::set(const TriangleSelector& selector) | ||||
| { | ||||
|     std::map<int, std::vector<bool>> sel_map = selector.serialize(); | ||||
|     if (sel_map != m_data) { | ||||
|         m_data = sel_map; | ||||
|         update_timestamp(); | ||||
|         this->touch(); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void FacetsAnnotation::clear() | ||||
| { | ||||
|     m_data.clear(); | ||||
|     update_timestamp(); | ||||
|     this->reset_timestamp(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Following function takes data from a triangle and encodes it as string
 | ||||
| // of hexadecimal numbers (one digit per triangle). Used for 3MF export,
 | ||||
| // changing it may break backwards compatibility !!!!!
 | ||||
|  | @ -1926,8 +1919,6 @@ std::string FacetsAnnotation::get_triangle_as_string(int triangle_idx) const | |||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Recover triangle splitting & state from string of hexadecimal values previously
 | ||||
| // generated by get_triangle_as_string. Used to load from 3MF.
 | ||||
| void FacetsAnnotation::set_triangle_from_string(int triangle_id, const std::string& str) | ||||
|  | @ -1951,12 +1942,8 @@ void FacetsAnnotation::set_triangle_from_string(int triangle_id, const std::stri | |||
|             code.insert(code.end(), bool(dec & (1 << i))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 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) | ||||
|  | @ -2024,7 +2011,7 @@ bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject | |||
|     assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART)); | ||||
|     assert(mo.volumes.size() == mo_new.volumes.size()); | ||||
|     for (size_t i=0; i<mo.volumes.size(); ++i) { | ||||
|         if (! mo_new.volumes[i]->m_supported_facets.is_same_as(mo.volumes[i]->m_supported_facets)) | ||||
|         if (! mo_new.volumes[i]->m_supported_facets.timestamp_matches(mo.volumes[i]->m_supported_facets)) | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
|  | @ -2034,7 +2021,7 @@ bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo | |||
|     assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART)); | ||||
|     assert(mo.volumes.size() == mo_new.volumes.size()); | ||||
|     for (size_t i=0; i<mo.volumes.size(); ++i) { | ||||
|         if (! mo_new.volumes[i]->m_seam_facets.is_same_as(mo.volumes[i]->m_seam_facets)) | ||||
|         if (! mo_new.volumes[i]->m_seam_facets.timestamp_matches(mo.volumes[i]->m_seam_facets)) | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
|  | @ -2050,7 +2037,7 @@ extern bool model_has_multi_part_objects(const Model &model) | |||
| 
 | ||||
| extern bool model_has_advanced_features(const Model &model) | ||||
| { | ||||
| 	auto config_is_advanced = [](const DynamicPrintConfig &config) { | ||||
| 	auto config_is_advanced = [](const ModelConfig &config) { | ||||
|         return ! (config.empty() || (config.size() == 1 && config.cbegin()->first == "extruder")); | ||||
| 	}; | ||||
|     for (const ModelObject *model_object : model.objects) { | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ | |||
| #include <string> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include <chrono> | ||||
| 
 | ||||
| namespace cereal { | ||||
| 	class BinaryInputArchive; | ||||
|  | @ -45,7 +44,7 @@ namespace UndoRedo { | |||
| 	class StackImpl; | ||||
| } | ||||
| 
 | ||||
| class ModelConfig : public ObjectBase, public DynamicPrintConfig | ||||
| class ModelConfigObject : public ObjectBase, public ModelConfig | ||||
| { | ||||
| private: | ||||
| 	friend class cereal::access; | ||||
|  | @ -56,20 +55,24 @@ private: | |||
| 
 | ||||
|     // Constructors to be only called by derived classes.
 | ||||
|     // Default constructor to assign a unique ID.
 | ||||
|     explicit ModelConfig() {} | ||||
|     explicit ModelConfigObject() {} | ||||
|     // Constructor with ignored int parameter to assign an invalid ID, to be replaced
 | ||||
|     // by an existing ID copied from elsewhere.
 | ||||
|     explicit ModelConfig(int) : ObjectBase(-1) {} | ||||
|     explicit ModelConfigObject(int) : ObjectBase(-1) {} | ||||
|     // Copy constructor copies the ID.
 | ||||
| 	explicit ModelConfig(const ModelConfig &cfg) : ObjectBase(-1), DynamicPrintConfig(cfg) { this->copy_id(cfg); } | ||||
| 	explicit ModelConfigObject(const ModelConfigObject &cfg) : ObjectBase(-1), ModelConfig(cfg) { this->copy_id(cfg); } | ||||
|     // Move constructor copies the ID.
 | ||||
| 	explicit ModelConfig(ModelConfig &&cfg) : ObjectBase(-1), DynamicPrintConfig(std::move(cfg)) { this->copy_id(cfg); } | ||||
| 	explicit ModelConfigObject(ModelConfigObject &&cfg) : ObjectBase(-1), ModelConfig(std::move(cfg)) { this->copy_id(cfg); } | ||||
| 
 | ||||
| 	ModelConfig& operator=(const ModelConfig &rhs) = default; | ||||
|     ModelConfig& operator=(ModelConfig &&rhs) = default; | ||||
|     Timestamp          timestamp() const throw() override { return this->ModelConfig::timestamp(); } | ||||
|     bool               object_id_and_timestamp_match(const ModelConfigObject &rhs) const throw() { return this->id() == rhs.id() && this->timestamp() == rhs.timestamp(); } | ||||
| 
 | ||||
|     // called by ModelObject::assign_copy()
 | ||||
| 	ModelConfigObject& operator=(const ModelConfigObject &rhs) = default; | ||||
|     ModelConfigObject& operator=(ModelConfigObject &&rhs) = default; | ||||
| 
 | ||||
|     template<class Archive> void serialize(Archive &ar) { | ||||
| 		ar(cereal::base_class<DynamicPrintConfig>(this)); | ||||
|         ar(cereal::base_class<ModelConfig>(this)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -136,7 +139,7 @@ public: | |||
|     // Attributes are defined by the AMF file format, but they don't seem to be used by Slic3r for any purpose.
 | ||||
|     t_model_material_attributes attributes; | ||||
|     // Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
 | ||||
|     ModelConfig config; | ||||
|     ModelConfigObject config; | ||||
| 
 | ||||
|     Model* get_model() const { return m_model; } | ||||
|     void apply(const t_model_material_attributes &attributes) | ||||
|  | @ -162,7 +165,7 @@ private: | |||
| 	ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); } | ||||
| 	template<class Archive> void serialize(Archive &ar) {  | ||||
| 		assert(this->id().invalid()); assert(this->config.id().invalid()); | ||||
| 		Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config); | ||||
| 		Internal::StaticSerializationWrapper<ModelConfigObject> config_wrapper(config); | ||||
| 		ar(attributes, config_wrapper); | ||||
| 		// assert(this->id().valid()); assert(this->config.id().valid());
 | ||||
| 	} | ||||
|  | @ -173,6 +176,23 @@ private: | |||
|     ModelMaterial& operator=(ModelMaterial &&rhs) = delete; | ||||
| }; | ||||
| 
 | ||||
| class LayerHeightProfile final : public ObjectWithTimestamp { | ||||
| public: | ||||
|     std::vector<coordf_t> get() const throw() { return m_data; } | ||||
|     bool                  empty() const throw() { return m_data.empty(); } | ||||
|     void                  set(const std::vector<coordf_t> &data) { if (m_data != data) { m_data = data; this->touch(); } } | ||||
|     void                  set(std::vector<coordf_t> &&data) { if (m_data != data) { m_data = std::move(data); this->touch(); } } | ||||
|     void                  clear() { m_data.clear(); this->touch(); } | ||||
| 
 | ||||
|     template<class Archive> void serialize(Archive &ar) | ||||
|     { | ||||
|         ar(cereal::base_class<ObjectWithTimestamp>(this), m_data); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::vector<coordf_t> m_data; | ||||
| }; | ||||
| 
 | ||||
| // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials),
 | ||||
| // and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
 | ||||
| // Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
 | ||||
|  | @ -189,12 +209,12 @@ public: | |||
|     // ModelVolumes are owned by this ModelObject.
 | ||||
|     ModelVolumePtrs         volumes; | ||||
|     // Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
 | ||||
|     ModelConfig      		config; | ||||
|     ModelConfigObject 		config; | ||||
|     // Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
 | ||||
|     t_layer_config_ranges   layer_config_ranges; | ||||
|     // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
 | ||||
|     // The pairs of <z, layer_height> are packed into a 1D array.
 | ||||
|     std::vector<coordf_t>   layer_height_profile; | ||||
|     LayerHeightProfile      layer_height_profile; | ||||
|     // Whether or not this object is printable
 | ||||
|     bool                    printable; | ||||
| 
 | ||||
|  | @ -381,8 +401,10 @@ private: | |||
| 	} | ||||
| 	template<class Archive> void serialize(Archive &ar) { | ||||
| 		ar(cereal::base_class<ObjectBase>(this)); | ||||
| 		Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config); | ||||
|         ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation, | ||||
| 		Internal::StaticSerializationWrapper<ModelConfigObject> config_wrapper(config); | ||||
|         Internal::StaticSerializationWrapper<LayerHeightProfile> layer_heigth_profile_wrapper(layer_height_profile); | ||||
|         ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper,  | ||||
|             sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation, | ||||
|             m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); | ||||
| 	} | ||||
| }; | ||||
|  | @ -403,34 +425,27 @@ enum class EnforcerBlockerType : int8_t { | |||
|     BLOCKER   = 2 | ||||
| }; | ||||
| 
 | ||||
| class FacetsAnnotation { | ||||
| class FacetsAnnotation final : public ObjectWithTimestamp { | ||||
| public: | ||||
|     using ClockType = std::chrono::steady_clock; | ||||
| 
 | ||||
|     const std::map<int, std::vector<bool>>& get_data() const { return m_data; } | ||||
|     void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) this->m_data = rhs.m_data; } | ||||
|     void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) this->m_data = rhs.m_data; } | ||||
|     const std::map<int, std::vector<bool>>& get_data() const throw() { return m_data; } | ||||
|     bool set(const TriangleSelector& selector); | ||||
|     indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const; | ||||
|     void clear(); | ||||
|     std::string get_triangle_as_string(int i) const; | ||||
|     void set_triangle_from_string(int triangle_id, const std::string& str); | ||||
| 
 | ||||
|     ClockType::time_point get_timestamp() const { return timestamp; } | ||||
|     bool is_same_as(const FacetsAnnotation& other) const { | ||||
|         return timestamp == other.get_timestamp(); | ||||
|     } | ||||
| private: | ||||
|     friend class cereal::access; | ||||
|     friend class UndoRedo::StackImpl; | ||||
| 
 | ||||
|     template<class Archive> void serialize(Archive &ar) | ||||
|     { | ||||
|         ar(m_data); | ||||
|         ar(cereal::base_class<ObjectWithTimestamp>(this), m_data); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::map<int, std::vector<bool>> m_data; | ||||
| 
 | ||||
|     ClockType::time_point timestamp; | ||||
|     void update_timestamp() { | ||||
|         timestamp = ClockType::now(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // An object STL, or a modifier volume, over which a different set of parameters shall be applied.
 | ||||
|  | @ -465,7 +480,7 @@ public: | |||
| 	void				reset_mesh() { m_mesh = std::make_shared<const TriangleMesh>(); } | ||||
|     // Configuration parameters specific to an object model geometry or a modifier volume, 
 | ||||
|     // overriding the global Slic3r settings and the ModelObject settings.
 | ||||
|     ModelConfig  		config; | ||||
|     ModelConfigObject	config; | ||||
| 
 | ||||
|     // List of mesh facets to be supported/unsupported.
 | ||||
|     FacetsAnnotation    m_supported_facets; | ||||
|  | @ -634,8 +649,9 @@ private: | |||
| 	} | ||||
| 	template<class Archive> void load(Archive &ar) { | ||||
| 		bool has_convex_hull; | ||||
|         ar(name, source, m_mesh, m_type, m_material_id, m_transformation, | ||||
|            m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets); | ||||
|         ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); | ||||
|         cereal::load_by_value(ar, m_supported_facets); | ||||
|         cereal::load_by_value(ar, m_seam_facets); | ||||
|         cereal::load_by_value(ar, config); | ||||
| 		assert(m_mesh); | ||||
| 		if (has_convex_hull) { | ||||
|  | @ -648,8 +664,9 @@ private: | |||
| 	} | ||||
| 	template<class Archive> void save(Archive &ar) const { | ||||
| 		bool has_convex_hull = m_convex_hull.get() != nullptr; | ||||
|         ar(name, source, m_mesh, m_type, m_material_id, m_transformation, | ||||
|            m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets); | ||||
|         ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); | ||||
|         cereal::save_by_value(ar, m_supported_facets); | ||||
|         cereal::save_by_value(ar, m_seam_facets); | ||||
|         cereal::save_by_value(ar, config); | ||||
| 		if (has_convex_hull) | ||||
| 			cereal::save_optional(ar, m_convex_hull); | ||||
|  | @ -935,7 +952,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2); | |||
| namespace cereal | ||||
| { | ||||
| 	template <class Archive> struct specialize<Archive, Slic3r::ModelVolume, cereal::specialization::member_load_save> {}; | ||||
| 	template <class Archive> struct specialize<Archive, Slic3r::ModelConfig, cereal::specialization::member_serialize> {}; | ||||
| 	template <class Archive> struct specialize<Archive, Slic3r::ModelConfigObject, cereal::specialization::member_serialize> {}; | ||||
| } | ||||
| 
 | ||||
| #endif /* slic3r_Model_hpp_ */ | ||||
|  |  | |||
|  | @ -17,6 +17,8 @@ ObjectID wipe_tower_instance_id() | |||
|     return mine.id(); | ||||
| } | ||||
| 
 | ||||
| ObjectWithTimestamp::Timestamp ObjectWithTimestamp::s_last_timestamp = 1; | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| // CEREAL_REGISTER_TYPE(Slic3r::ObjectBase)
 | ||||
|  |  | |||
|  | @ -49,12 +49,14 @@ private: | |||
| class ObjectBase | ||||
| { | ||||
| public: | ||||
|     using Timestamp = uint64_t; | ||||
| 
 | ||||
|     ObjectID     		id() const { return m_id; } | ||||
|     // Return an optional timestamp of this object.
 | ||||
|     // If the timestamp returned is non-zero, then the serialization framework will
 | ||||
|     // only save this object on the Undo/Redo stack if the timestamp is different
 | ||||
|     // from the timestmap of the object at the top of the Undo / Redo stack.
 | ||||
|     virtual uint64_t	timestamp() const { return 0; } | ||||
|     virtual Timestamp	timestamp() const { return 0; } | ||||
| 
 | ||||
| protected: | ||||
|     // Constructors to be only called by derived classes.
 | ||||
|  | @ -91,6 +93,42 @@ private: | |||
|   	template<class Archive> static void load_and_construct(Archive & ar, cereal::construct<ObjectBase> &construct) { ObjectID id; ar(id); construct(id); } | ||||
| }; | ||||
| 
 | ||||
| class ObjectWithTimestamp : public ObjectBase | ||||
| { | ||||
| protected: | ||||
|     // Constructors to be only called by derived classes.
 | ||||
|     // Default constructor to assign a new timestamp unique to this object's history.
 | ||||
| 	ObjectWithTimestamp() = default; | ||||
|     // Constructor with ignored int parameter to assign an invalid ID, to be replaced
 | ||||
|     // by an existing ID copied from elsewhere.
 | ||||
|     ObjectWithTimestamp(int) : ObjectBase(-1) {} | ||||
| 	// The class tree will have virtual tables and type information.
 | ||||
| 	virtual ~ObjectWithTimestamp() = default; | ||||
| 
 | ||||
|     // Resetting timestamp to 1 indicates the object is in its initial (cleared) state.
 | ||||
|     // To be called by the derived class's clear() method.
 | ||||
|     void                reset_timestamp() { m_timestamp = 1; } | ||||
| 
 | ||||
| public: | ||||
|     // Return an optional timestamp of this object.
 | ||||
|     // If the timestamp returned is non-zero, then the serialization framework will
 | ||||
|     // only save this object on the Undo/Redo stack if the timestamp is different
 | ||||
|     // from the timestmap of the object at the top of the Undo / Redo stack.
 | ||||
|     Timestamp	        timestamp() const throw() override { return m_timestamp; } | ||||
|     bool 				timestamp_matches(const ObjectWithTimestamp &rhs) const throw() { return m_timestamp == rhs.m_timestamp; } | ||||
|     bool 				object_id_and_timestamp_match(const ObjectWithTimestamp &rhs) const throw() { return this->id() == rhs.id() && m_timestamp == rhs.m_timestamp; } | ||||
|     void 				touch() { m_timestamp = ++ s_last_timestamp; } | ||||
| 
 | ||||
| private: | ||||
| 	// The first timestamp is non-zero, as zero timestamp means the timestamp is not reliable.
 | ||||
| 	Timestamp 			m_timestamp { 1 }; | ||||
|     static Timestamp    s_last_timestamp; | ||||
| 	 | ||||
| 	friend class cereal::access; | ||||
| 	friend class Slic3r::UndoRedo::StackImpl; | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(m_timestamp); } | ||||
| }; | ||||
| 
 | ||||
| // Unique object / instance ID for the wipe tower.
 | ||||
| extern ObjectID wipe_tower_object_id(); | ||||
| extern ObjectID wipe_tower_instance_id(); | ||||
|  |  | |||
|  | @ -403,8 +403,10 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, | |||
|         assert(mv_src.id() == mv_dst.id()); | ||||
|         // Copy the ModelVolume data.
 | ||||
|         mv_dst.name   = mv_src.name; | ||||
| 		static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config); | ||||
| 		mv_dst.config.assign_config(mv_src.config); | ||||
|         if (! mv_dst.m_supported_facets.timestamp_matches(mv_src.m_supported_facets)) | ||||
|             mv_dst.m_supported_facets = mv_src.m_supported_facets; | ||||
|         if (! mv_dst.m_seam_facets.timestamp_matches(mv_src.m_seam_facets)) | ||||
|             mv_dst.m_seam_facets = mv_src.m_seam_facets; | ||||
|         //FIXME what to do with the materials?
 | ||||
|         // mv_dst.m_material_id = mv_src.m_material_id;
 | ||||
|  | @ -585,7 +587,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
| 	new_full_config.option("print_settings_id",    true); | ||||
| 	new_full_config.option("filament_settings_id", true); | ||||
| 	new_full_config.option("printer_settings_id",  true); | ||||
|     new_full_config.normalize(); | ||||
|     new_full_config.normalize_fdm(); | ||||
| 
 | ||||
|     // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
 | ||||
| 	t_config_option_keys print_diff, object_diff, region_diff, full_config_diff; | ||||
|  | @ -644,7 +646,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|             m_ranges.reserve(in.size()); | ||||
|             // Input ranges are sorted lexicographically. First range trims the other ranges.
 | ||||
|             coordf_t last_z = 0; | ||||
|             for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in) | ||||
|             for (const std::pair<const t_layer_height_range, ModelConfig> &range : in) | ||||
| 				if (range.first.second > last_z) { | ||||
|                     coordf_t min_z = std::max(range.first.first, 0.); | ||||
|                     if (min_z > last_z + EPSILON) { | ||||
|  | @ -652,7 +654,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|                         last_z = min_z; | ||||
|                     } | ||||
|                     if (range.first.second > last_z + EPSILON) { | ||||
| 						const DynamicPrintConfig* cfg = &range.second; | ||||
| 						const DynamicPrintConfig *cfg = &range.second.get(); | ||||
|                         m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg); | ||||
|                         last_z = range.first.second; | ||||
|                     } | ||||
|  | @ -842,11 +844,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|         // Only volume IDs, volume types, transformation matrices and their order are checked, configuration and other parameters are NOT checked.
 | ||||
|         bool model_parts_differ         = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); | ||||
|         bool modifiers_differ           = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER); | ||||
|         bool support_blockers_differ    = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER); | ||||
|         bool support_enforcers_differ   = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER); | ||||
|         bool supports_differ            = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER) || | ||||
|                                           model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER); | ||||
|         if (model_parts_differ || modifiers_differ ||  | ||||
|             model_object.origin_translation != model_object_new.origin_translation   || | ||||
|             model_object.layer_height_profile       != model_object_new.layer_height_profile || | ||||
|             ! model_object.layer_height_profile.timestamp_matches(model_object_new.layer_height_profile) || | ||||
|             ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty())) { | ||||
|             // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
 | ||||
|             auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); | ||||
|  | @ -856,27 +858,28 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|             } | ||||
|             // Copy content of the ModelObject including its ID, do not change the parent.
 | ||||
|             model_object.assign_copy(model_object_new); | ||||
|         } else if (support_blockers_differ || support_enforcers_differ || model_custom_supports_data_changed(model_object, model_object_new)) { | ||||
|         } else if (supports_differ || model_custom_supports_data_changed(model_object, model_object_new)) { | ||||
|             // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
 | ||||
|             if (supports_differ) { | ||||
|                 this->call_cancel_callback(); | ||||
|                 update_apply_status(false); | ||||
|             } | ||||
|             // 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) | ||||
|                 update_apply_status(it->print_object->invalidate_step(posSupportMaterial)); | ||||
|             if (support_enforcers_differ || support_blockers_differ) { | ||||
|             if (supports_differ) { | ||||
|                 // Copy just the support volumes.
 | ||||
|                 model_volume_list_update_supports(model_object, model_object_new); | ||||
|             } | ||||
|         } | ||||
|         if (model_custom_seam_data_changed(model_object, model_object_new)) { | ||||
|         } else if (model_custom_seam_data_changed(model_object, model_object_new)) { | ||||
|             update_apply_status(this->invalidate_step(psGCodeExport)); | ||||
|         } | ||||
|         if (! model_parts_differ && ! modifiers_differ) { | ||||
|             // Synchronize Object's config.
 | ||||
|             bool object_config_changed = model_object.config != model_object_new.config; | ||||
|             bool object_config_changed = ! model_object.config.timestamp_matches(model_object_new.config); | ||||
| 			if (object_config_changed) | ||||
| 				static_cast<DynamicPrintConfig&>(model_object.config) = static_cast<const DynamicPrintConfig&>(model_object_new.config); | ||||
| 				model_object.config.assign_config(model_object_new.config); | ||||
|             if (! object_diff.empty() || object_config_changed || num_extruders_changed) { | ||||
|                 PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders); | ||||
|                 auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); | ||||
|  | @ -940,13 +943,20 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|                         old.emplace_back(&(*it)); | ||||
|             } | ||||
|             // Generate a list of trafos and XY offsets for instances of a ModelObject
 | ||||
|             PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders); | ||||
|             // Producing the config for PrintObject on demand, caching it at print_object_last.
 | ||||
|             const PrintObject *print_object_last = nullptr; | ||||
|             auto print_object_apply_config = [this, &print_object_last, model_object, num_extruders](PrintObject* print_object) { | ||||
|                 print_object->config_apply(print_object_last ? | ||||
|                     print_object_last->config() : | ||||
|                     PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders)); | ||||
|                 print_object_last = print_object; | ||||
|             }; | ||||
|             std::vector<PrintObjectTrafoAndInstances> new_print_instances = print_objects_from_model_object(*model_object); | ||||
|             if (old.empty()) { | ||||
|                 // Simple case, just generate new instances.
 | ||||
|                 for (PrintObjectTrafoAndInstances &print_instances : new_print_instances) { | ||||
|                     PrintObject *print_object = new PrintObject(this, model_object, print_instances.trafo, std::move(print_instances.instances)); | ||||
|                     print_object->config_apply(config); | ||||
|                     print_object_apply_config(print_object); | ||||
|                     print_objects_new.emplace_back(print_object); | ||||
|                     // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
 | ||||
|                     new_objects = true; | ||||
|  | @ -963,7 +973,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
| 				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, new_instances.trafo, std::move(new_instances.instances)); | ||||
|                     print_object->config_apply(config); | ||||
|                     print_object_apply_config(print_object); | ||||
|                     print_objects_new.emplace_back(print_object); | ||||
|                     // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
 | ||||
|                     new_objects = true; | ||||
|  | @ -1577,7 +1587,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const | |||
|         ModelVolume *volume = model_object->volumes[volume_id]; | ||||
|         //FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned.
 | ||||
|         if ((volume->is_model_part() || volume->is_modifier()) && ! volume->material_id().empty() && ! volume->config.has("extruder")) | ||||
|             volume->config.opt<ConfigOptionInt>("extruder", true)->value = int(volume_id + 1); | ||||
|             volume->config.set("extruder", int(volume_id + 1)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3233,7 +3233,7 @@ PrinterTechnology printer_technology(const ConfigBase &cfg) | |||
|     return ptUnknown; | ||||
| } | ||||
| 
 | ||||
| void DynamicPrintConfig::normalize() | ||||
| void DynamicPrintConfig::normalize_fdm() | ||||
| { | ||||
|     if (this->has("extruder")) { | ||||
|         int extruder = this->option("extruder")->getInt(); | ||||
|  | @ -3718,6 +3718,8 @@ void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std:: | |||
|     } | ||||
| } | ||||
| 
 | ||||
| uint64_t ModelConfig::s_last_timestamp = 1; | ||||
| 
 | ||||
| static Points to_points(const std::vector<Vec2d> &dpts) | ||||
| { | ||||
|     Points pts; pts.reserve(dpts.size()); | ||||
|  |  | |||
|  | @ -254,7 +254,7 @@ public: | |||
|     // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
 | ||||
|     const ConfigDef*    def() const override { return &print_config_def; } | ||||
| 
 | ||||
|     void                normalize(); | ||||
|     void                normalize_fdm(); | ||||
| 
 | ||||
|     void 				set_num_extruders(unsigned int num_extruders); | ||||
| 
 | ||||
|  | @ -269,14 +269,6 @@ public: | |||
|         { PrintConfigDef::handle_legacy(opt_key, value); } | ||||
| }; | ||||
| 
 | ||||
| template<typename CONFIG> | ||||
| void normalize_and_apply_config(CONFIG &dst, const DynamicPrintConfig &src) | ||||
| { | ||||
|     DynamicPrintConfig src_normalized(src); | ||||
|     src_normalized.normalize(); | ||||
|     dst.apply(src_normalized, true); | ||||
| } | ||||
| 
 | ||||
| class StaticPrintConfig : public StaticConfig | ||||
| { | ||||
| public: | ||||
|  | @ -1369,6 +1361,94 @@ Points get_bed_shape(const DynamicPrintConfig &cfg); | |||
| Points get_bed_shape(const PrintConfig &cfg); | ||||
| Points get_bed_shape(const SLAPrinterConfig &cfg); | ||||
| 
 | ||||
| // ModelConfig is a wrapper around DynamicPrintConfig with an addition of a timestamp.
 | ||||
| // Each change of ModelConfig is tracked by assigning a new timestamp from a global counter.
 | ||||
| // The counter is used for faster synchronization of the background slicing thread
 | ||||
| // with the front end by skipping synchronization of equal config dictionaries. 
 | ||||
| // The global counter is also used for avoiding unnecessary serialization of config 
 | ||||
| // dictionaries when taking an Undo snapshot.
 | ||||
| //
 | ||||
| // The global counter is NOT thread safe, therefore it is recommended to use ModelConfig from
 | ||||
| // the main thread only.
 | ||||
| // 
 | ||||
| // As there is a global counter and it is being increased with each change to any ModelConfig,
 | ||||
| // if two ModelConfig dictionaries differ, they should differ with their timestamp as well.
 | ||||
| // Therefore copying the ModelConfig including its timestamp is safe as there is no harm
 | ||||
| // in having multiple ModelConfig with equal timestamps as long as their dictionaries are equal.
 | ||||
| //
 | ||||
| // The timestamp is used by the Undo/Redo stack. As zero timestamp means invalid timestamp
 | ||||
| // to the Undo/Redo stack (zero timestamp means the Undo/Redo stack needs to serialize and
 | ||||
| // compare serialized data for differences), zero timestamp shall never be used.
 | ||||
| // Timestamp==1 shall only be used for empty dictionaries.
 | ||||
| class ModelConfig | ||||
| { | ||||
| public: | ||||
|     void         clear() { m_data.clear(); m_timestamp = 1; } | ||||
| 
 | ||||
|     // Modification of the ModelConfig is not thread safe due to the global timestamp counter!
 | ||||
|     // Don't call modification methods from the back-end!
 | ||||
|     void         assign_config(const ModelConfig &rhs) { | ||||
|         if (m_timestamp != rhs.m_timestamp) { | ||||
|             m_data      = rhs.m_data; | ||||
|             m_timestamp = rhs.m_timestamp; | ||||
|         } | ||||
|     } | ||||
|     void         assign_config(ModelConfig &&rhs) { | ||||
|         if (m_timestamp != rhs.m_timestamp) { | ||||
|             m_data      = std::move(rhs.m_data); | ||||
|             m_timestamp = rhs.m_timestamp; | ||||
|             rhs.clear(); | ||||
|         } | ||||
|     } | ||||
|     // Assign methods don't assign if src==dst to not having to bump the timestamp in case they are equal.
 | ||||
|     void         assign_config(const DynamicPrintConfig &rhs)  { if (m_data != rhs) { m_data = rhs; this->touch(); } } | ||||
|     void         assign_config(DynamicPrintConfig &&rhs)       { if (m_data != rhs) { m_data = std::move(rhs); this->touch(); } } | ||||
|     void         apply(const ModelConfig &other, bool ignore_nonexistent = false) { this->apply(other.get(), ignore_nonexistent); } | ||||
|     void         apply(const ConfigBase &other, bool ignore_nonexistent = false) { m_data.apply_only(other, other.keys(), ignore_nonexistent); this->touch(); } | ||||
|     void         apply_only(const ModelConfig &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->apply_only(other.get(), keys, ignore_nonexistent); } | ||||
|     void         apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { m_data.apply_only(other, keys, ignore_nonexistent); this->touch(); } | ||||
|     bool         set_key_value(const std::string &opt_key, ConfigOption *opt) { bool out = m_data.set_key_value(opt_key, opt); this->touch(); return out; } | ||||
|     template<typename T> | ||||
|     void         set(const std::string &opt_key, T value) { m_data.set(opt_key, value, true); this->touch(); } | ||||
|     void         set_deserialize(const t_config_option_key &opt_key, const std::string &str, bool append = false) | ||||
|         { m_data.set_deserialize(opt_key, str, append); this->touch(); } | ||||
|     bool         erase(const t_config_option_key &opt_key) { bool out = m_data.erase(opt_key); if (out) this->touch(); return out; } | ||||
| 
 | ||||
|     // Getters are thread safe.
 | ||||
|     // The following implicit conversion breaks the Cereal serialization.
 | ||||
| //    operator const DynamicPrintConfig&() const throw() { return this->get(); }
 | ||||
|     const DynamicPrintConfig&   get() const throw() { return m_data; } | ||||
|     bool                        empty() const throw() { return m_data.empty(); } | ||||
|     size_t                      size() const throw() { return m_data.size(); } | ||||
|     auto                        cbegin() const { return m_data.cbegin(); } | ||||
|     auto                        cend() const { return m_data.cend(); } | ||||
|     t_config_option_keys        keys() const { return m_data.keys(); } | ||||
|     bool                        has(const t_config_option_key &opt_key) const { return m_data.has(opt_key); } | ||||
|     const ConfigOption*         option(const t_config_option_key &opt_key) const { return m_data.option(opt_key); } | ||||
|     int                         opt_int(const t_config_option_key &opt_key) const { return m_data.opt_int(opt_key); } | ||||
|     int                         extruder() const { return opt_int("extruder"); } | ||||
|     double                      opt_float(const t_config_option_key &opt_key) const { return m_data.opt_float(opt_key); } | ||||
|     std::string                 opt_serialize(const t_config_option_key &opt_key) const { return m_data.opt_serialize(opt_key); } | ||||
| 
 | ||||
|     // Return an optional timestamp of this object.
 | ||||
|     // If the timestamp returned is non-zero, then the serialization framework will
 | ||||
|     // only save this object on the Undo/Redo stack if the timestamp is different
 | ||||
|     // from the timestmap of the object at the top of the Undo / Redo stack.
 | ||||
|     virtual uint64_t    timestamp() const throw() { return m_timestamp; } | ||||
|     bool                timestamp_matches(const ModelConfig &rhs) const throw() { return m_timestamp == rhs.m_timestamp; } | ||||
|     // Not thread safe! Should not be called from other than the main thread!
 | ||||
|     void                touch() { m_timestamp = ++ s_last_timestamp; } | ||||
| 
 | ||||
| private: | ||||
|     friend class cereal::access; | ||||
|     template<class Archive> void serialize(Archive& ar) { ar(m_timestamp); ar(m_data); } | ||||
| 
 | ||||
|     uint64_t                    m_timestamp { 1 }; | ||||
|     DynamicPrintConfig          m_data; | ||||
| 
 | ||||
|     static uint64_t             s_last_timestamp; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| // Serialization through the Cereal library
 | ||||
|  |  | |||
|  | @ -440,7 +440,7 @@ std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare | |||
|     using namespace FillAdaptive; | ||||
| 
 | ||||
|     auto [adaptive_line_spacing, support_line_spacing] = adaptive_fill_line_spacing(*this); | ||||
|     if (adaptive_line_spacing == 0. && support_line_spacing == 0. || this->layers().empty()) | ||||
|     if ((adaptive_line_spacing == 0. && support_line_spacing == 0.) || this->layers().empty()) | ||||
|         return std::make_pair(OctreePtr(), OctreePtr()); | ||||
| 
 | ||||
|     indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set(); | ||||
|  | @ -1544,22 +1544,48 @@ static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders | |||
| PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders) | ||||
| { | ||||
|     PrintObjectConfig config = default_object_config; | ||||
|     normalize_and_apply_config(config, object.config); | ||||
|     { | ||||
|         DynamicPrintConfig src_normalized(object.config.get()); | ||||
|         src_normalized.normalize_fdm(); | ||||
|         config.apply(src_normalized, true); | ||||
|     } | ||||
|     // Clamp invalid extruders to the default extruder (with index 1).
 | ||||
|     clamp_exturder_to_default(config.support_material_extruder,           num_extruders); | ||||
|     clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders); | ||||
|     return config; | ||||
| } | ||||
| 
 | ||||
| static void apply_to_print_region_config(PrintRegionConfig &out, const DynamicPrintConfig &in) | ||||
| { | ||||
|     // 1) Copy the "extruder key to infill_extruder and perimeter_extruder.
 | ||||
|     std::string sextruder = "extruder"; | ||||
|     auto *opt_extruder = in.opt<ConfigOptionInt>(sextruder); | ||||
|     if (opt_extruder) { | ||||
|         int extruder = opt_extruder->value; | ||||
|         if (extruder != 0) { | ||||
|             out.infill_extruder      .value = extruder; | ||||
|             out.solid_infill_extruder.value = extruder; | ||||
|             out.perimeter_extruder   .value = extruder; | ||||
|         } | ||||
|     } | ||||
|     // 2) Copy the rest of the values.
 | ||||
|     for (auto it = in.cbegin(); it != in.cend(); ++ it) | ||||
|         if (it->first != sextruder) { | ||||
|             ConfigOption *my_opt = out.option(it->first, false); | ||||
|             if (my_opt) | ||||
|                 my_opt->set(it->second.get()); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders) | ||||
| { | ||||
|     PrintRegionConfig config = default_region_config; | ||||
|     normalize_and_apply_config(config, volume.get_object()->config); | ||||
|     apply_to_print_region_config(config, volume.get_object()->config.get()); | ||||
|     if (layer_range_config != nullptr) | ||||
|     	normalize_and_apply_config(config, *layer_range_config); | ||||
|     normalize_and_apply_config(config, volume.config); | ||||
|     	apply_to_print_region_config(config, *layer_range_config); | ||||
|     apply_to_print_region_config(config, volume.config.get()); | ||||
|     if (! volume.material_id().empty()) | ||||
|         normalize_and_apply_config(config, volume.material()->config); | ||||
|         apply_to_print_region_config(config, volume.material()->config.get()); | ||||
|     // Clamp invalid extruders to the default extruder (with index 1).
 | ||||
|     clamp_exturder_to_default(config.infill_extruder,       num_extruders); | ||||
|     clamp_exturder_to_default(config.perimeter_extruder,    num_extruders); | ||||
|  | @ -1592,13 +1618,13 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full | |||
| 				print_config, | ||||
| 				region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders), | ||||
| 				object_extruders); | ||||
| 			for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range_and_config : model_object.layer_config_ranges) | ||||
| 			for (const std::pair<const t_layer_height_range, ModelConfig> &range_and_config : model_object.layer_config_ranges) | ||||
| 				if (range_and_config.second.has("perimeter_extruder") || | ||||
| 					range_and_config.second.has("infill_extruder") || | ||||
| 					range_and_config.second.has("solid_infill_extruder")) | ||||
| 					PrintRegion::collect_object_printing_extruders( | ||||
| 						print_config, | ||||
| 						region_config_from_model_volume(default_region_config, &range_and_config.second, *model_volume, num_extruders), | ||||
| 						region_config_from_model_volume(default_region_config, &range_and_config.second.get(), *model_volume, num_extruders), | ||||
| 						object_extruders); | ||||
| 		} | ||||
|     sort_remove_duplicates(object_extruders); | ||||
|  | @ -1626,7 +1652,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c | |||
| 
 | ||||
|     if (layer_height_profile.empty()) { | ||||
|         // use the constructor because the assignement is crashing on ASAN OsX
 | ||||
|         layer_height_profile = std::vector<coordf_t>(model_object.layer_height_profile); | ||||
|         layer_height_profile = std::vector<coordf_t>(model_object.layer_height_profile.get()); | ||||
| //        layer_height_profile = model_object.layer_height_profile;
 | ||||
|         updated = true; | ||||
|     } | ||||
|  | @ -2872,7 +2898,7 @@ void PrintObject::project_and_append_custom_facets( | |||
| 
 | ||||
|         // Now append the collected polygons to respective layers.
 | ||||
|         for (auto& trg : projections_of_triangles) { | ||||
|             int layer_id = trg.first_layer_id; | ||||
|             int layer_id = int(trg.first_layer_id); | ||||
|             for (const LightPolygon& poly : trg.polygons) { | ||||
|                 if (layer_id >= int(expolys.size())) | ||||
|                     break; // part of triangle could be projected above top layer
 | ||||
|  |  | |||
|  | @ -185,7 +185,6 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con | |||
|     config.option("sla_print_settings_id",    true); | ||||
|     config.option("sla_material_settings_id", true); | ||||
|     config.option("printer_settings_id",      true); | ||||
|     config.normalize(); | ||||
|     // Collect changes to print config.
 | ||||
|     t_config_option_keys print_diff    = m_print_config.diff(config); | ||||
|     t_config_option_keys printer_diff  = m_printer_config.diff(config); | ||||
|  | @ -395,12 +394,12 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con | |||
|                 model_object.assign_copy(model_object_new); | ||||
|             } else { | ||||
|                 // Synchronize Object's config.
 | ||||
|                 bool object_config_changed = model_object.config != model_object_new.config; | ||||
|                 bool object_config_changed = ! model_object.config.timestamp_matches(model_object_new.config); | ||||
|                 if (object_config_changed) | ||||
|                     static_cast<DynamicPrintConfig&>(model_object.config) = static_cast<const DynamicPrintConfig&>(model_object_new.config); | ||||
|                     model_object.config.assign_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); | ||||
|                     new_config.apply(model_object.config.get(), true); | ||||
|                     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()) { | ||||
|  | @ -464,9 +463,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con | |||
| 
 | ||||
|             print_object->set_instances(std::move(new_instances)); | ||||
| 
 | ||||
|             SLAPrintObjectConfig new_config = m_default_object_config; | ||||
|             normalize_and_apply_config(new_config, model_object.config); | ||||
|             print_object->config_apply(new_config, true); | ||||
|             print_object->config_apply(m_default_object_config, true); | ||||
|             print_object->config_apply(model_object.config.get(), true); | ||||
|             print_objects_new.emplace_back(print_object); | ||||
|             new_objects = true; | ||||
|         } | ||||
|  |  | |||
|  | @ -261,7 +261,7 @@ protected: | |||
| 	SLAPrintObject(SLAPrint* print, ModelObject* model_object); | ||||
|     ~SLAPrintObject(); | ||||
| 
 | ||||
|     void                    config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } | ||||
|     void                    config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { 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); } | ||||
| 
 | ||||
|  |  | |||
|  | @ -170,24 +170,15 @@ SlicingParameters SlicingParameters::create_from_config( | |||
|     return params; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges) | ||||
| { | ||||
| 	std::vector<std::pair<t_layer_height_range, coordf_t>> out; | ||||
| 	out.reserve(config_ranges.size()); | ||||
| 	for (const auto &kvp : config_ranges) | ||||
| 		out.emplace_back(kvp.first, kvp.second.option("layer_height")->getFloat()); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| // Convert layer_config_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
 | ||||
| // in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
 | ||||
| std::vector<coordf_t> layer_height_profile_from_ranges( | ||||
| 	const SlicingParameters 	&slicing_params, | ||||
| 	const t_layer_config_ranges &layer_config_ranges)                           // #ys_FIXME_experiment
 | ||||
| 	const t_layer_config_ranges &layer_config_ranges) | ||||
| { | ||||
|     // 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
 | ||||
|     std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping; | ||||
|     ranges_non_overlapping.reserve(layer_config_ranges.size() * 4);             // #ys_FIXME_experiment
 | ||||
|     ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); | ||||
|     if (slicing_params.first_object_layer_height_fixed()) | ||||
|         ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>( | ||||
|             t_layer_height_range(0., slicing_params.first_object_layer_height),  | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ namespace Slic3r | |||
| 
 | ||||
| class PrintConfig; | ||||
| class PrintObjectConfig; | ||||
| class ModelConfig; | ||||
| class ModelObject; | ||||
| class DynamicPrintConfig; | ||||
| 
 | ||||
|  | @ -128,9 +129,7 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters | |||
| } | ||||
| 
 | ||||
| typedef std::pair<coordf_t,coordf_t> t_layer_height_range; | ||||
| typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges; | ||||
| 
 | ||||
| extern std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges); | ||||
| typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges; | ||||
| 
 | ||||
| extern std::vector<coordf_t> layer_height_profile_from_ranges( | ||||
|     const SlicingParameters     &slicing_params, | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include "ConfigManipulation.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "libslic3r/Model.hpp" | ||||
| #include "libslic3r/PresetBundle.hpp" | ||||
| 
 | ||||
| #include <wx/msgdlg.h> | ||||
|  |  | |||
|  | @ -10,9 +10,11 @@ | |||
| 
 | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| #include "Field.hpp" | ||||
| //#include <boost-1_70/boost/any.hpp>
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class ModelConfig; | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| class ConfigManipulation | ||||
|  | @ -24,13 +26,13 @@ class ConfigManipulation | |||
|     std::function<Field* (const std::string&, int opt_index)>   get_field = nullptr; | ||||
|     // callback to propagation of changed value, if needed 
 | ||||
|     std::function<void(const std::string&, const boost::any&)>  cb_value_change = nullptr; | ||||
|     DynamicPrintConfig* local_config = nullptr; | ||||
|     ModelConfig* local_config = nullptr; | ||||
| 
 | ||||
| public: | ||||
|     ConfigManipulation(std::function<void()> load_config, | ||||
|         std::function<Field* (const std::string&, int opt_index)> get_field, | ||||
|         std::function<void(const std::string&, const boost::any&)>  cb_value_change, | ||||
|         DynamicPrintConfig* local_config = nullptr) : | ||||
|         ModelConfig* local_config = nullptr) : | ||||
|         load_config(load_config), | ||||
|         get_field(get_field), | ||||
|         cb_value_change(cb_value_change), | ||||
|  |  | |||
|  | @ -511,7 +511,7 @@ void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas | |||
| { | ||||
|     this->update_slicing_parameters(); | ||||
|     m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, quality_factor); | ||||
|     const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile; | ||||
|     const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile); | ||||
|     m_layers_texture.valid = false; | ||||
|     canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); | ||||
| } | ||||
|  | @ -520,7 +520,7 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, | |||
| { | ||||
|     this->update_slicing_parameters(); | ||||
|     m_layer_height_profile = smooth_height_profile(m_layer_height_profile, *m_slicing_parameters, smoothing_params); | ||||
|     const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile; | ||||
|     const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile); | ||||
|     m_layers_texture.valid = false; | ||||
|     canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); | ||||
| } | ||||
|  | @ -560,7 +560,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas) | |||
|     if (last_object_id >= 0) { | ||||
|         if (m_layer_height_profile_modified) { | ||||
|             wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Manual edit"))); | ||||
|             const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile; | ||||
|             const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile); | ||||
| 			canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -153,7 +153,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus | |||
|      | ||||
| void ObjectLayers::create_layers_list() | ||||
| { | ||||
|     for (const auto layer : m_object->layer_config_ranges) | ||||
|     for (const auto &layer : m_object->layer_config_ranges) | ||||
|     { | ||||
|         const t_layer_height_range& range = layer.first; | ||||
|         auto del_btn = new PlusMinusButton(m_parent, m_bmp_delete, range); | ||||
|  |  | |||
|  | @ -468,7 +468,7 @@ int ObjectList::get_selected_obj_idx() const | |||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) const  | ||||
| ModelConfig& ObjectList::get_item_config(const wxDataViewItem& item) const  | ||||
| { | ||||
|     assert(item); | ||||
|     const ItemType type = m_objects_model->GetItemType(item); | ||||
|  | @ -492,10 +492,10 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) | |||
|         auto object = (*m_objects)[i]; | ||||
|         wxString extruder; | ||||
|         if (!object->config.has("extruder") || | ||||
|             size_t(object->config.option<ConfigOptionInt>("extruder")->value) > max_extruder) | ||||
|             size_t(object->config.extruder()) > max_extruder) | ||||
|             extruder = _(L("default")); | ||||
|         else | ||||
|             extruder = wxString::Format("%d", object->config.option<ConfigOptionInt>("extruder")->value); | ||||
|             extruder = wxString::Format("%d", object->config.extruder()); | ||||
| 
 | ||||
|         m_objects_model->SetExtruder(extruder, item); | ||||
| 
 | ||||
|  | @ -504,10 +504,10 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) | |||
|                 item = m_objects_model->GetItemByVolumeId(i, id); | ||||
|                 if (!item) continue; | ||||
|                 if (!object->volumes[id]->config.has("extruder") || | ||||
|                     size_t(object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value) > max_extruder) | ||||
|                     size_t(object->volumes[id]->config.extruder()) > max_extruder) | ||||
|                     extruder = _(L("default")); | ||||
|                 else | ||||
|                     extruder = wxString::Format("%d", object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value);  | ||||
|                     extruder = wxString::Format("%d", object->volumes[id]->config.extruder());  | ||||
| 
 | ||||
|                 m_objects_model->SetExtruder(extruder, item); | ||||
|             } | ||||
|  | @ -767,8 +767,7 @@ void ObjectList::copy_settings_to_clipboard() | |||
|     if (m_objects_model->GetItemType(item) & itSettings) | ||||
|         item = m_objects_model->GetParent(item); | ||||
| 
 | ||||
|     DynamicPrintConfig& config_cache = m_clipboard.get_config_cache(); | ||||
|     config_cache = get_item_config(item); | ||||
|     m_clipboard.get_config_cache() = get_item_config(item).get(); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::paste_settings_into_list() | ||||
|  | @ -799,7 +798,7 @@ void ObjectList::paste_settings_into_list() | |||
|     } | ||||
| 
 | ||||
|     // Add settings item for object/sub-object and show them 
 | ||||
|     show_settings(add_settings_item(item, m_config)); | ||||
|     show_settings(add_settings_item(item, &m_config->get())); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes) | ||||
|  | @ -818,8 +817,8 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol | |||
|     { | ||||
|         const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(object_item, wxString::FromUTF8(volume->name.c_str()), volume->type(),  | ||||
|             volume->get_mesh_errors_count()>0 , | ||||
|             volume->config.has("extruder") ? volume->config.option<ConfigOptionInt>("extruder")->value : 0); | ||||
|         add_settings_item(vol_item, &volume->config); | ||||
|             volume->config.has("extruder") ? volume->config.extruder() : 0); | ||||
|         add_settings_item(vol_item, &volume->config.get()); | ||||
|         items.Add(vol_item); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1480,7 +1479,7 @@ void ObjectList::get_settings_choice(const wxString& category_name) | |||
|     // Add settings item for object/sub-object and show them 
 | ||||
|     if (!(item_type & (itObject | itVolume | itLayer))) | ||||
|         item = m_objects_model->GetTopParent(item); | ||||
|     show_settings(add_settings_item(item, m_config)); | ||||
|     show_settings(add_settings_item(item, &m_config->get())); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::get_freq_settings_choice(const wxString& bundle_name) | ||||
|  | @ -1537,7 +1536,7 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) | |||
|     // Add settings item for object/sub-object and show them 
 | ||||
|     if (!(item_type & (itObject | itVolume | itLayer))) | ||||
|         item = m_objects_model->GetTopParent(item); | ||||
|     show_settings(add_settings_item(item, m_config)); | ||||
|     show_settings(add_settings_item(item, &m_config->get())); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::show_settings(const wxDataViewItem settings_item) | ||||
|  | @ -1821,9 +1820,8 @@ void ObjectList::append_menu_item_change_extruder(wxMenu* menu) | |||
| 
 | ||||
|     int initial_extruder = -1; // negative value for multiple object/part selection
 | ||||
|     if (sels.Count()==1) { | ||||
|         DynamicPrintConfig& config = get_item_config(sels[0]); | ||||
|         initial_extruder = !config.has("extruder") ? 0 :  | ||||
|                             config.option<ConfigOptionInt>("extruder")->value; | ||||
|         const ModelConfig &config = get_item_config(sels[0]); | ||||
|         initial_extruder = config.has("extruder") ? config.extruder() : 0; | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i <= extruders_cnt; i++) | ||||
|  | @ -2320,9 +2318,7 @@ void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item) | |||
| 
 | ||||
|     take_snapshot(_(L("Delete Settings"))); | ||||
| 
 | ||||
|     int extruder = -1; | ||||
|     if (m_config->has("extruder")) | ||||
|         extruder = m_config->option<ConfigOptionInt>("extruder")->value; | ||||
|     int extruder = m_config->has("extruder") ? m_config->extruder() : -1; | ||||
| 
 | ||||
|     coordf_t layer_height = 0.0; | ||||
|     if (is_layer_settings) | ||||
|  | @ -2459,11 +2455,10 @@ void ObjectList::split() | |||
|         const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name), | ||||
|             volume->is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, | ||||
|             volume->get_mesh_errors_count()>0, | ||||
|             volume->config.has("extruder") ? | ||||
|             volume->config.option<ConfigOptionInt>("extruder")->value : 0, | ||||
|             volume->config.has("extruder") ? volume->config.extruder() : 0, | ||||
|             false); | ||||
|         // add settings to the part, if it has those
 | ||||
|         add_settings_item(vol_item, &volume->config); | ||||
|         add_settings_item(vol_item, &volume->config.get()); | ||||
|     } | ||||
| 
 | ||||
|     model_object->input_file.clear(); | ||||
|  | @ -2579,7 +2574,7 @@ void ObjectList::merge(bool to_multipart_object) | |||
|         Model* model = (*m_objects)[0]->get_model(); | ||||
|         ModelObject* new_object = model->add_object(); | ||||
|         new_object->name = _u8L("Merged"); | ||||
|         DynamicPrintConfig* config = &new_object->config; | ||||
|         ModelConfig &config = new_object->config; | ||||
| 
 | ||||
|         for (int obj_idx : obj_idxs) | ||||
|         { | ||||
|  | @ -2616,8 +2611,8 @@ void ObjectList::merge(bool to_multipart_object) | |||
|             } | ||||
| 
 | ||||
|             // merge settings
 | ||||
|             auto new_opt_keys = config->keys(); | ||||
|             const DynamicPrintConfig& from_config = object->config; | ||||
|             auto new_opt_keys = config.keys(); | ||||
|             const ModelConfig& from_config = object->config; | ||||
|             auto opt_keys = from_config.keys(); | ||||
| 
 | ||||
|             for (auto& opt_key : opt_keys) { | ||||
|  | @ -2628,7 +2623,7 @@ void ObjectList::merge(bool to_multipart_object) | |||
|                         // get it from default config values
 | ||||
|                         option = DynamicPrintConfig::new_from_defaults_keys({ opt_key })->option(opt_key); | ||||
|                     } | ||||
|                     config->set_key_value(opt_key, option->clone()); | ||||
|                     config.set_key_value(opt_key, option->clone()); | ||||
|                 } | ||||
|             } | ||||
|             // save extruder value if it was set
 | ||||
|  | @ -2695,7 +2690,7 @@ void ObjectList::layers_editing() | |||
|         // set some default value
 | ||||
|         if (ranges.empty()) { | ||||
|             take_snapshot(_(L("Add Layers"))); | ||||
|             ranges[{ 0.0f, 2.0f }] = get_default_layer_config(obj_idx); | ||||
|             ranges[{ 0.0f, 2.0f }].assign_config(get_default_layer_config(obj_idx)); | ||||
|         } | ||||
| 
 | ||||
|         // create layer root item
 | ||||
|  | @ -3011,8 +3006,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) | |||
|     auto model_object = (*m_objects)[obj_idx]; | ||||
|     const wxString& item_name = from_u8(model_object->name); | ||||
|     const auto item = m_objects_model->Add(item_name, | ||||
|                       !model_object->config.has("extruder") ? 0 : | ||||
|                       model_object->config.option<ConfigOptionInt>("extruder")->value, | ||||
|                       model_object->config.has("extruder") ? model_object->config.extruder() : 0, | ||||
|                       get_mesh_errors_count(obj_idx) > 0); | ||||
| 
 | ||||
|     // add volumes to the object
 | ||||
|  | @ -3022,10 +3016,9 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) | |||
|                 from_u8(volume->name), | ||||
|                 volume->type(), | ||||
|                 volume->get_mesh_errors_count()>0, | ||||
|                 !volume->config.has("extruder") ? 0 : | ||||
|                 volume->config.option<ConfigOptionInt>("extruder")->value, | ||||
|                 volume->config.has("extruder") ? volume->config.extruder() : 0, | ||||
|                 false); | ||||
|             add_settings_item(vol_item, &volume->config); | ||||
|             add_settings_item(vol_item, &volume->config.get()); | ||||
|         } | ||||
|         Expand(item); | ||||
|     } | ||||
|  | @ -3045,7 +3038,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) | |||
|         m_objects_model->SetPrintableState(model_object->instances[0]->printable ? piPrintable : piUnprintable, obj_idx); | ||||
| 
 | ||||
|     // add settings to the object, if it has those
 | ||||
|     add_settings_item(item, &model_object->config); | ||||
|     add_settings_item(item, &model_object->config.get()); | ||||
| 
 | ||||
|     // Add layers if it has
 | ||||
|     add_layer_root_item(item); | ||||
|  | @ -3123,7 +3116,7 @@ void ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it | |||
|                 if ((*m_objects)[item->obj_idx]->volumes.size() == 1 &&  | ||||
|                     (*m_objects)[item->obj_idx]->config.has("extruder")) | ||||
|                 { | ||||
|                     const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option<ConfigOptionInt>("extruder")->value); | ||||
|                     const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.extruder()); | ||||
|                     m_objects_model->SetExtruder(extruder, m_objects_model->GetItemById(item->obj_idx)); | ||||
|                 } | ||||
|                 wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx); | ||||
|  | @ -3289,7 +3282,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range curren | |||
| 
 | ||||
|     const wxDataViewItem layers_item = GetSelection(); | ||||
| 
 | ||||
|     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges; | ||||
|     auto& ranges = object(obj_idx)->layer_config_ranges; | ||||
|     auto it_range = ranges.find(current_range); | ||||
|     assert(it_range != ranges.end()); | ||||
|     if (it_range == ranges.end()) | ||||
|  | @ -3305,7 +3298,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range curren | |||
|         changed = true; | ||||
| 
 | ||||
|         const t_layer_height_range new_range = { current_range.second, current_range.second + 2. }; | ||||
|         ranges[new_range] = get_default_layer_config(obj_idx); | ||||
|         ranges[new_range].assign_config(get_default_layer_config(obj_idx)); | ||||
|         add_layer_item(new_range, layers_item); | ||||
|     } | ||||
|     else if (const std::pair<coordf_t, coordf_t> &next_range = it_next_range->first; current_range.second <= next_range.first) | ||||
|  | @ -3342,7 +3335,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range curren | |||
|                     add_layer_item(new_range, layers_item, layer_idx); | ||||
| 
 | ||||
|                     new_range = { current_range.second, middle_layer_z }; | ||||
|                     ranges[new_range] = get_default_layer_config(obj_idx); | ||||
|                     ranges[new_range].assign_config(get_default_layer_config(obj_idx)); | ||||
|                     add_layer_item(new_range, layers_item, layer_idx); | ||||
|                 } | ||||
|             } | ||||
|  | @ -3353,7 +3346,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range curren | |||
|                 changed = true; | ||||
| 
 | ||||
|                 const t_layer_height_range new_range = { current_range.second, next_range.first }; | ||||
|                 ranges[new_range] = get_default_layer_config(obj_idx); | ||||
|                 ranges[new_range].assign_config(get_default_layer_config(obj_idx)); | ||||
|                 add_layer_item(new_range, layers_item, layer_idx); | ||||
|             } | ||||
|         } | ||||
|  | @ -3379,7 +3372,7 @@ wxString ObjectList::can_add_new_range_after_current(const t_layer_height_range | |||
|         // This should not happen.
 | ||||
|         return "ObjectList assert"; | ||||
| 
 | ||||
|     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges; | ||||
|     auto& ranges = object(obj_idx)->layer_config_ranges; | ||||
|     auto it_range = ranges.find(current_range); | ||||
|     assert(it_range != ranges.end()); | ||||
|     if (it_range == ranges.end()) | ||||
|  | @ -3418,7 +3411,7 @@ void ObjectList::add_layer_item(const t_layer_height_range& range, | |||
|     const int obj_idx = m_objects_model->GetObjectIdByItem(layers_item); | ||||
|     if (obj_idx < 0) return; | ||||
| 
 | ||||
|     const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range]; | ||||
|     const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range].get(); | ||||
|     if (!config.has("extruder")) | ||||
|         return; | ||||
| 
 | ||||
|  | @ -3438,7 +3431,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t la | |||
|     if (obj_idx < 0)  | ||||
|         return false; | ||||
| 
 | ||||
|     DynamicPrintConfig* config = &object(obj_idx)->layer_config_ranges[range]; | ||||
|     ModelConfig* config = &object(obj_idx)->layer_config_ranges[range]; | ||||
|     if (fabs(layer_height - config->opt_float("layer_height")) < EPSILON) | ||||
|         return false; | ||||
| 
 | ||||
|  | @ -3467,12 +3460,14 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay | |||
| 
 | ||||
|     const ItemType sel_type = m_objects_model->GetItemType(GetSelection()); | ||||
| 
 | ||||
|     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges; | ||||
| 
 | ||||
|     const DynamicPrintConfig config = ranges[range]; | ||||
|     auto& ranges = object(obj_idx)->layer_config_ranges; | ||||
| 
 | ||||
|     { | ||||
|         ModelConfig config = std::move(ranges[range]); | ||||
|         ranges.erase(range); | ||||
|     ranges[new_range] = config; | ||||
|         ranges[new_range] = std::move(config); | ||||
|     } | ||||
| 
 | ||||
|     changed_object(obj_idx); | ||||
|      | ||||
|     wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx)); | ||||
|  | @ -4040,7 +4035,7 @@ void ObjectList::change_part_type() | |||
|     } | ||||
|     else if (!settings_item &&  | ||||
|               (new_type == ModelVolumeType::MODEL_PART || new_type == ModelVolumeType::PARAMETER_MODIFIER)) { | ||||
|         add_settings_item(item, &volume->config); | ||||
|         add_settings_item(item, &volume->config.get()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -4065,14 +4060,14 @@ void ObjectList::update_and_show_object_settings_item() | |||
|     if (!item) return; | ||||
| 
 | ||||
|     const wxDataViewItem& obj_item = m_objects_model->IsSettingsItem(item) ? m_objects_model->GetParent(item) : item; | ||||
|     select_item(add_settings_item(obj_item, &get_item_config(obj_item))); | ||||
|     select_item(add_settings_item(obj_item, &get_item_config(obj_item).get())); | ||||
| } | ||||
| 
 | ||||
| // Update settings item for item had it
 | ||||
| void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections) | ||||
| { | ||||
|     const wxDataViewItem old_settings_item = m_objects_model->GetSettingsItem(item); | ||||
|     const wxDataViewItem new_settings_item = add_settings_item(item, &get_item_config(item)); | ||||
|     const wxDataViewItem new_settings_item = add_settings_item(item, &get_item_config(item).get()); | ||||
| 
 | ||||
|     if (!new_settings_item && old_settings_item) | ||||
|         m_objects_model->Delete(old_settings_item); | ||||
|  | @ -4489,19 +4484,19 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const | |||
| 
 | ||||
|     for (const wxDataViewItem& item : sels) | ||||
|     { | ||||
|         DynamicPrintConfig& config = get_item_config(item); | ||||
|         ModelConfig& config = get_item_config(item); | ||||
|          | ||||
|         if (config.has("extruder")) { | ||||
|             if (extruder == 0) | ||||
|                 config.erase("extruder"); | ||||
|             else | ||||
|                 config.option<ConfigOptionInt>("extruder")->value = extruder; | ||||
|                 config.set("extruder", extruder); | ||||
|         } | ||||
|         else if (extruder > 0) | ||||
|             config.set_key_value("extruder", new ConfigOptionInt(extruder)); | ||||
| 
 | ||||
|         const wxString extruder_str = extruder == 0 ? wxString (_(L("default"))) :  | ||||
|                                       wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value); | ||||
|                                       wxString::Format("%d", config.extruder()); | ||||
| 
 | ||||
|         auto const type = m_objects_model->GetItemType(item); | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ class MenuWithSeparators; | |||
| namespace Slic3r { | ||||
| class ConfigOptionsGroup; | ||||
| class DynamicPrintConfig; | ||||
| class ModelConfig; | ||||
| class ModelObject; | ||||
| class ModelVolume; | ||||
| class TriangleMesh; | ||||
|  | @ -41,7 +42,7 @@ typedef std::vector<ModelVolume*> ModelVolumePtrs; | |||
| 
 | ||||
| typedef double                                       coordf_t; | ||||
| typedef std::pair<coordf_t, coordf_t>                t_layer_height_range; | ||||
| typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges; | ||||
| typedef std::map<t_layer_height_range, ModelConfig>  t_layer_config_ranges; | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
|  | @ -165,7 +166,7 @@ private: | |||
|     wxMenuItem* m_menu_item_split_instances { nullptr }; | ||||
| 
 | ||||
|     ObjectDataViewModel         *m_objects_model{ nullptr }; | ||||
|     DynamicPrintConfig          *m_config {nullptr}; | ||||
|     ModelConfig                 *m_config {nullptr}; | ||||
|     std::vector<ModelObject*>   *m_objects{ nullptr }; | ||||
| 
 | ||||
|     wxBitmapComboBox            *m_extruder_editor { nullptr }; | ||||
|  | @ -210,7 +211,7 @@ public: | |||
|     std::map<std::string, wxBitmap> CATEGORY_ICON; | ||||
| 
 | ||||
|     ObjectDataViewModel*        GetModel() const    { return m_objects_model; } | ||||
|     DynamicPrintConfig*         config() const      { return m_config; } | ||||
|     ModelConfig*                config() const      { return m_config; } | ||||
|     std::vector<ModelObject*>*  objects() const     { return m_objects; } | ||||
| 
 | ||||
|     ModelObject*                object(const int obj_idx) const ; | ||||
|  | @ -320,7 +321,7 @@ public: | |||
|     wxPoint             get_mouse_position_in_control() const { return wxGetMousePosition() - this->GetScreenPosition(); } | ||||
|     wxBoxSizer*         get_sizer() {return  m_sizer;} | ||||
|     int                 get_selected_obj_idx() const; | ||||
|     DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const; | ||||
|     ModelConfig&        get_item_config(const wxDataViewItem& item) const; | ||||
|     SettingsBundle      get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings); | ||||
| 
 | ||||
|     void                changed_object(const int obj_idx = -1) const; | ||||
|  |  | |||
|  | @ -82,7 +82,7 @@ bool ObjectSettings::update_settings_list() | |||
|         return false; | ||||
| 
 | ||||
|     const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject; | ||||
| 	SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_object_settings); | ||||
| 	SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(&config->get(), is_object_settings); | ||||
| 
 | ||||
|     if (!cat_options.empty()) | ||||
|     { | ||||
|  | @ -176,7 +176,7 @@ bool ObjectSettings::update_settings_list() | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ObjectSettings::add_missed_options(DynamicPrintConfig* config_to, const DynamicPrintConfig& config_from) | ||||
| bool ObjectSettings::add_missed_options(ModelConfig* config_to, const DynamicPrintConfig& config_from) | ||||
| { | ||||
|     bool is_added = false; | ||||
|     if (wxGetApp().plater()->printer_technology() == ptFFF) | ||||
|  | @ -193,7 +193,7 @@ bool ObjectSettings::add_missed_options(DynamicPrintConfig* config_to, const Dyn | |||
|     return is_added; | ||||
| } | ||||
| 
 | ||||
| void ObjectSettings::update_config_values(DynamicPrintConfig* config) | ||||
| void ObjectSettings::update_config_values(ModelConfig* config) | ||||
| { | ||||
|     const auto objects_model        = wxGetApp().obj_list()->GetModel(); | ||||
|     const auto item                 = wxGetApp().obj_list()->GetSelection(); | ||||
|  | @ -250,14 +250,12 @@ void ObjectSettings::update_config_values(DynamicPrintConfig* config) | |||
|     { | ||||
|         const int obj_idx = objects_model->GetObjectIdByItem(item); | ||||
|         assert(obj_idx >= 0); | ||||
|         DynamicPrintConfig* obj_config = &wxGetApp().model().objects[obj_idx]->config; | ||||
| 
 | ||||
|         main_config.apply(*obj_config, true); | ||||
|         main_config.apply(wxGetApp().model().objects[obj_idx]->config.get(), true); | ||||
|         printer_technology == ptFFF  ?  config_manipulation.update_print_fff_config(&main_config) : | ||||
|                                         config_manipulation.update_print_sla_config(&main_config) ; | ||||
|     } | ||||
| 
 | ||||
|     main_config.apply(*config, true); | ||||
|     main_config.apply(config->get(), true); | ||||
|     printer_technology == ptFFF  ?  config_manipulation.update_print_fff_config(&main_config) : | ||||
|                                     config_manipulation.update_print_sla_config(&main_config) ; | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ class wxBoxSizer; | |||
| 
 | ||||
| namespace Slic3r { | ||||
| class DynamicPrintConfig; | ||||
| class ModelConfig; | ||||
| namespace GUI { | ||||
| class ConfigOptionsGroup; | ||||
| 
 | ||||
|  | @ -52,8 +53,8 @@ public: | |||
|      * Example: if Infill is set to 100%, and Fill Pattern is missed in config_to, | ||||
|      * we should add fill_pattern to avoid endless loop in update | ||||
|      */ | ||||
|     bool        add_missed_options(DynamicPrintConfig *config_to, const DynamicPrintConfig &config_from); | ||||
|     void        update_config_values(DynamicPrintConfig*config); | ||||
|     bool        add_missed_options(ModelConfig *config_to, const DynamicPrintConfig &config_from); | ||||
|     void        update_config_values(ModelConfig *config); | ||||
|     void        UpdateAndShow(const bool show) override; | ||||
|     void        msw_rescale(); | ||||
| }; | ||||
|  |  | |||
|  | @ -466,7 +466,7 @@ GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const | |||
|     if (! mo) | ||||
|         return out; | ||||
| 
 | ||||
|     const DynamicPrintConfig& object_cfg = mo->config; | ||||
|     const DynamicPrintConfig& object_cfg = mo->config.get(); | ||||
|     const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; | ||||
|     std::unique_ptr<DynamicPrintConfig> default_cfg = nullptr; | ||||
| 
 | ||||
|  | @ -556,7 +556,7 @@ RENDER_AGAIN: | |||
|         auto opts = get_config_options({"hollowing_enable"}); | ||||
|         m_enable_hollowing = static_cast<const ConfigOptionBool*>(opts[0].first)->value; | ||||
|         if (m_imgui->checkbox(m_desc["enable"], m_enable_hollowing)) { | ||||
|             mo->config.opt<ConfigOptionBool>("hollowing_enable", true)->value = m_enable_hollowing; | ||||
|             mo->config.set("hollowing_enable", m_enable_hollowing); | ||||
|             wxGetApp().obj_list()->update_and_show_object_settings_item(); | ||||
|             config_changed = true; | ||||
|         } | ||||
|  | @ -618,14 +618,14 @@ RENDER_AGAIN: | |||
|     } | ||||
|     if (slider_edited || slider_released) { | ||||
|         if (slider_released) { | ||||
|             mo->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = m_offset_stash; | ||||
|             mo->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = m_quality_stash; | ||||
|             mo->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = m_closing_d_stash; | ||||
|             mo->config.set("hollowing_min_thickness", m_offset_stash); | ||||
|             mo->config.set("hollowing_quality", m_quality_stash); | ||||
|             mo->config.set("hollowing_closing_distance", m_closing_d_stash); | ||||
|             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Hollowing parameter change"))); | ||||
|         } | ||||
|         mo->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = offset; | ||||
|         mo->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = quality; | ||||
|         mo->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = closing_d; | ||||
|         mo->config.set("hollowing_min_thickness", offset); | ||||
|         mo->config.set("hollowing_quality", quality); | ||||
|         mo->config.set("hollowing_closing_distance", closing_d); | ||||
|         if (slider_released) { | ||||
|             wxGetApp().obj_list()->update_and_show_object_settings_item(); | ||||
|             config_changed = true; | ||||
|  |  | |||
|  | @ -546,7 +546,7 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st | |||
|     if (! mo) | ||||
|         return out; | ||||
| 
 | ||||
|     const DynamicPrintConfig& object_cfg = mo->config; | ||||
|     const DynamicPrintConfig& object_cfg = mo->config.get(); | ||||
|     const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; | ||||
|     std::unique_ptr<DynamicPrintConfig> default_cfg = nullptr; | ||||
| 
 | ||||
|  | @ -753,15 +753,15 @@ RENDER_AGAIN: | |||
|             m_density_stash = density; | ||||
|         } | ||||
|         if (slider_edited) { | ||||
|             mo->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance; | ||||
|             mo->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density; | ||||
|             mo->config.set("support_points_minimal_distance", minimal_point_distance); | ||||
|             mo->config.set("support_points_density_relative", (int)density); | ||||
|         } | ||||
|         if (slider_released) { | ||||
|             mo->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash; | ||||
|             mo->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)m_density_stash; | ||||
|             mo->config.set("support_points_minimal_distance", m_minimal_point_distance_stash); | ||||
|             mo->config.set("support_points_density_relative", (int)m_density_stash); | ||||
|             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support parameter change"))); | ||||
|             mo->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance; | ||||
|             mo->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density; | ||||
|             mo->config.set("support_points_minimal_distance", minimal_point_distance); | ||||
|             mo->config.set("support_points_density_relative", (int)density); | ||||
|             wxGetApp().obj_list()->update_and_show_object_settings_item(); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -414,7 +414,7 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index | |||
| 	m_opt_map.emplace(opt_id, pair); | ||||
| 
 | ||||
| 	if (m_show_modified_btns) // fill group and category values just fro options from Settings Tab 
 | ||||
| 	    wxGetApp().sidebar().get_searcher().add_key(opt_id, title, config_category); | ||||
| 	    wxGetApp().sidebar().get_searcher().add_key(opt_id, title, this->config_category()); | ||||
| 
 | ||||
| 	return Option(*m_config->def()->get(opt_key), opt_id); | ||||
| } | ||||
|  | @ -431,12 +431,10 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b | |||
| 		}		 | ||||
| 
 | ||||
| 		auto 				itOption  = it->second; | ||||
| 		std::string opt_key = itOption.first; | ||||
| 		const std::string  &opt_key   = itOption.first; | ||||
| 		int 			    opt_index = itOption.second; | ||||
| 
 | ||||
| 		auto option = m_options.at(opt_id).opt; | ||||
| 
 | ||||
| 		change_opt_value(*m_config, opt_key, value, opt_index == -1 ? 0 : opt_index); | ||||
| 		this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index); | ||||
| 	} | ||||
| 
 | ||||
| 	OptionsGroup::on_change_OG(opt_id, value);  | ||||
|  | @ -470,7 +468,7 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, | |||
| 		     opt_key == "bed_shape"				|| opt_key == "filament_ramming_parameters" ||  | ||||
| 		     opt_key == "compatible_printers"	|| opt_key == "compatible_prints" ) { | ||||
|         value = get_config_value(config, opt_key); | ||||
|         change_opt_value(*m_config, opt_key, value); | ||||
|         this->change_opt_value(opt_key, value); | ||||
|         return; | ||||
|     } | ||||
| 	else | ||||
|  | @ -789,6 +787,15 @@ Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int op | |||
| 	return opt_id.empty() ? nullptr : get_field(opt_id); | ||||
| } | ||||
| 
 | ||||
| // Change an option on m_config, possibly call ModelConfig::touch().
 | ||||
| void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) | ||||
| 
 | ||||
| { | ||||
| 	Slic3r::GUI::change_opt_value(const_cast<DynamicPrintConfig&>(*m_config), opt_key, value, opt_index); | ||||
| 	if (m_modelconfig) | ||||
| 		m_modelconfig->touch(); | ||||
| } | ||||
| 
 | ||||
| void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/) | ||||
| { | ||||
| 	SetLabel(value); | ||||
|  |  | |||
|  | @ -221,18 +221,18 @@ protected: | |||
| 
 | ||||
| class ConfigOptionsGroup: public OptionsGroup { | ||||
| public: | ||||
| 	ConfigOptionsGroup(	wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr,  | ||||
| 	ConfigOptionsGroup(	wxWindow* parent, const wxString& title, DynamicPrintConfig* config = nullptr,  | ||||
| 						bool is_tab_opt = false, column_t extra_clmn = nullptr) : | ||||
| 		OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(_config) {} | ||||
| 		OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(config) {} | ||||
| 	ConfigOptionsGroup(	wxWindow* parent, const wxString& title, ModelConfig* config,  | ||||
| 						bool is_tab_opt = false, column_t extra_clmn = nullptr) : | ||||
| 		OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(&config->get()), m_modelconfig(config) {} | ||||
| 
 | ||||
|     /// reference to libslic3r config, non-owning pointer (?).
 | ||||
|     DynamicPrintConfig*		m_config {nullptr}; | ||||
|     bool					m_full_labels {0}; | ||||
| 	t_opt_map				m_opt_map; | ||||
| 	const std::string& config_category() const throw() { return m_config_category; } | ||||
| 	const t_opt_map&   opt_map() const throw() { return m_opt_map; } | ||||
| 
 | ||||
|     std::string             config_category; | ||||
| 
 | ||||
|     void        set_config(DynamicPrintConfig* config) { m_config = config; } | ||||
| 	void 		set_config_category(const std::string &category) { this->m_config_category = category; } | ||||
|     void        set_config(DynamicPrintConfig* config) { m_config = config; m_modelconfig = nullptr; } | ||||
| 	Option		get_option(const std::string& opt_key, int opt_index = -1); | ||||
| 	Line		create_single_option_line(const std::string& title, int idx = -1) /*const*/{ | ||||
| 		Option option = get_option(title, idx); | ||||
|  | @ -266,6 +266,20 @@ public: | |||
| 	// return option value from config 
 | ||||
| 	boost::any	get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1); | ||||
| 	Field*		get_fieldc(const t_config_option_key& opt_key, int opt_index); | ||||
| 
 | ||||
| private: | ||||
|     // Reference to libslic3r config or ModelConfig::get(), non-owning pointer.
 | ||||
|     // The reference is const, so that the spots which modify m_config are clearly
 | ||||
|     // demarcated by const_cast and m_config_changed_callback is called afterwards.
 | ||||
|     const DynamicPrintConfig*	m_config {nullptr}; | ||||
|     // If the config is modelconfig, then ModelConfig::touch() has to be called after value change.
 | ||||
|     ModelConfig*				m_modelconfig { nullptr }; | ||||
| 	bool						m_full_labels{ 0 }; | ||||
| 	t_opt_map					m_opt_map; | ||||
|     std::string             	m_config_category; | ||||
| 
 | ||||
|     // Change an option on m_config, possibly call ModelConfig::touch().
 | ||||
| 	void 	change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); | ||||
| }; | ||||
| 
 | ||||
| //  Static text shown among the options.
 | ||||
|  |  | |||
|  | @ -1364,7 +1364,7 @@ void Selection::copy_to_clipboard() | |||
|         ModelObject* dst_object = m_clipboard.add_object(); | ||||
|         dst_object->name                 = src_object->name; | ||||
|         dst_object->input_file           = src_object->input_file; | ||||
| 		static_cast<DynamicPrintConfig&>(dst_object->config) = static_cast<const DynamicPrintConfig&>(src_object->config); | ||||
| 		dst_object->config.assign_config(src_object->config); | ||||
|         dst_object->sla_support_points   = src_object->sla_support_points; | ||||
|         dst_object->sla_points_status    = src_object->sla_points_status; | ||||
|         dst_object->sla_drain_holes      = src_object->sla_drain_holes; | ||||
|  |  | |||
|  | @ -675,8 +675,8 @@ void Tab::update_changed_tree_ui() | |||
|             { | ||||
|                 if (!sys_page && modified_page) | ||||
|                     break; | ||||
|                 for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { | ||||
|                     const std::string& opt_key = it->first; | ||||
|                 for (const auto &kvp : group->opt_map()) { | ||||
|                     const std::string& opt_key = kvp.first; | ||||
|                     get_sys_and_mod_flags(opt_key, sys_page, modified_page); | ||||
|                 } | ||||
|             } | ||||
|  | @ -764,7 +764,7 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) | |||
|                         is_empty ? m_compatible_prints.btn->Disable() : m_compatible_prints.btn->Enable(); | ||||
|                     } | ||||
|                 } | ||||
|                 for (auto kvp : group->m_opt_map) { | ||||
|                 for (const auto &kvp : group->opt_map()) { | ||||
|                     const std::string& opt_key = kvp.first; | ||||
|                     if ((m_options_list[opt_key] & os) == 0) | ||||
|                         to_sys ? group->back_to_sys_value(opt_key) : group->back_to_initial_value(opt_key); | ||||
|  | @ -3791,7 +3791,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la | |||
| 
 | ||||
|     //! config_ have to be "right"
 | ||||
|     ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(this, title, m_config, true, extra_column); | ||||
|     optgroup->config_category = m_title.ToStdString(); | ||||
|     optgroup->set_config_category(m_title.ToStdString()); | ||||
|     if (noncommon_label_width >= 0) | ||||
|         optgroup->label_width = noncommon_label_width; | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| #define CEREAL_FUTURE_EXPERIMENTAL | ||||
| #include <cereal/archives/adapters.hpp> | ||||
| 
 | ||||
| #include <libslic3r/Config.hpp> | ||||
| #include <libslic3r/PrintConfig.hpp> | ||||
| #include <libslic3r/ObjectID.hpp> | ||||
| #include <libslic3r/Utils.hpp> | ||||
| 
 | ||||
|  |  | |||
|  | @ -219,7 +219,7 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo | |||
|     my $config = Slic3r::Config->new; | ||||
|     $config->set('extruder', 2); | ||||
|     $config->set('perimeter_extruder', 3); | ||||
|     $config->normalize; | ||||
|     $config->normalize_fdm; | ||||
|     ok !$config->has('extruder'), 'extruder option is removed after normalize()'; | ||||
|     is $config->get('infill_extruder'), 2, 'undefined extruder is populated with default extruder'; | ||||
|     is $config->get('perimeter_extruder'), 3, 'defined extruder is not overwritten by default extruder'; | ||||
|  | @ -228,7 +228,7 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo | |||
| { | ||||
|     my $config = Slic3r::Config->new; | ||||
|     $config->set('infill_extruder', 2); | ||||
|     $config->normalize; | ||||
|     $config->normalize_fdm; | ||||
|     is $config->get('solid_infill_extruder'), 2, 'undefined solid infill extruder is populated with infill extruder'; | ||||
| } | ||||
| 
 | ||||
|  | @ -236,7 +236,7 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo | |||
|     my $config = Slic3r::Config->new; | ||||
|     $config->set('spiral_vase', 1); | ||||
|     $config->set('retract_layer_change', [1,0]); | ||||
|     $config->normalize; | ||||
|     $config->normalize_fdm; | ||||
|     is_deeply $config->get('retract_layer_change'), [0,0], 'retract_layer_change is disabled with spiral_vase'; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -48,7 +48,7 @@ | |||
|         %code{% THIS->apply(*other, true); %}; | ||||
|     %name{get_keys} std::vector<std::string> keys(); | ||||
|     void erase(t_config_option_key opt_key); | ||||
|     void normalize(); | ||||
|     void normalize_fdm(); | ||||
|     %name{setenv} void setenv_(); | ||||
|     double min_object_distance() %code{% RETVAL = Slic3r::min_object_distance(*THIS); %}; | ||||
|     static DynamicPrintConfig* load(char *path) | ||||
|  |  | |||
|  | @ -118,7 +118,7 @@ load_stl(CLASS, path, object_name) | |||
|         %code%{ RETVAL = THIS->get_model(); %}; | ||||
| 
 | ||||
|     Ref<DynamicPrintConfig> config() | ||||
|         %code%{ RETVAL = &THIS->config; %}; | ||||
|         %code%{ RETVAL = &const_cast<DynamicPrintConfig&>(THIS->config.get()); %}; | ||||
|      | ||||
|     std::string get_attribute(std::string name) | ||||
|         %code%{ if (THIS->attributes.find(name) != THIS->attributes.end()) RETVAL = THIS->attributes[name]; %}; | ||||
|  | @ -202,7 +202,7 @@ ModelMaterial::attributes() | |||
|     void set_input_file(std::string value) | ||||
|         %code%{ THIS->input_file = value; %}; | ||||
|     Ref<DynamicPrintConfig> config() | ||||
|         %code%{ RETVAL = &THIS->config; %}; | ||||
|         %code%{ RETVAL = &const_cast<DynamicPrintConfig&>(THIS->config.get()); %}; | ||||
| 
 | ||||
|     Ref<Model> model() | ||||
|         %code%{ RETVAL = THIS->get_model(); %}; | ||||
|  | @ -248,7 +248,7 @@ ModelMaterial::attributes() | |||
|     Ref<ModelMaterial> material(); | ||||
|      | ||||
|     Ref<DynamicPrintConfig> config() | ||||
|         %code%{ RETVAL = &THIS->config; %}; | ||||
|         %code%{ RETVAL = &const_cast<DynamicPrintConfig&>(THIS->config.get()); %}; | ||||
|     Ref<TriangleMesh> mesh() | ||||
|         %code%{ RETVAL = &THIS->mesh(); %}; | ||||
|      | ||||
|  |  | |||
|  | @ -139,7 +139,18 @@ _constant() | |||
|         %}; | ||||
|          | ||||
|     bool apply(Model *model, DynamicPrintConfig* config) | ||||
|         %code%{ RETVAL = THIS->apply(*model, *config); %}; | ||||
|         %code%{  | ||||
|             // Touching every config as the Perl bindings does not correctly export ModelConfig, | ||||
|             // therefore the configs have often invalid timestamps. | ||||
|             for (auto obj : model->objects) { | ||||
|                 obj->config.touch(); | ||||
|                 for (auto vol : obj->volumes) | ||||
|                     vol->config.touch(); | ||||
|             } | ||||
|             for (auto mat : model->materials) | ||||
|                 mat.second->config.touch(); | ||||
|             RETVAL = THIS->apply(*model, *config); | ||||
|         %}; | ||||
|     bool has_infinite_skirt(); | ||||
|     std::vector<unsigned int> extruders() const; | ||||
|     int validate() %code%{  | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv