diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 8db4a24d4..105db05c9 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -48,14 +48,16 @@ const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format const std::string CONTENT_TYPES_FILE = "[Content_Types].xml"; const std::string RELATIONSHIPS_FILE = "_rels/.rels"; const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png"; -const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r.config"; -const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_model.config"; -const std::string PRINT_SUPER_CONFIG_FILE = "Metadata/SuperSlicer.config"; -const std::string MODEL_SUPER_CONFIG_FILE = "Metadata/SuperSlicer_model.config"; -const std::string PRINT_PRUSA_CONFIG_FILE = "Metadata/Slic3r_PE.config"; -const std::string MODEL_PRUSA_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; +const std::string SLIC3R_PRINT_CONFIG_FILE = "Metadata/Slic3r.config"; +const std::string SLIC3R_MODEL_CONFIG_FILE = "Metadata/Slic3r_model.config"; +const std::string SLIC3R_LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; +const std::string SUPER_PRINT_CONFIG_FILE = "Metadata/SuperSlicer.config"; +const std::string SUPER_MODEL_CONFIG_FILE = "Metadata/SuperSlicer_model.config"; +const std::string SUPER_LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; +const std::string PRUSA_PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config"; +const std::string PRUSA_MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; +const std::string PRUSA_LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt"; -const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt"; const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt"; const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"; @@ -590,6 +592,34 @@ namespace Slic3r { XML_StopParser(m_xml_parser, false); } + template + void convert_from_prusa(CONFIG_CLASS& conf, const DynamicPrintConfig& global_config) { + //void convert_from_prusa(DynamicPrintConfig& conf, const DynamicPrintConfig & global_config) { + //void convert_from_prusa(ModelConfigObject& conf, const DynamicPrintConfig& global_config) { + for (const t_config_option_key& opt_key : conf.keys()) { + const ConfigOption* opt = conf.option(opt_key); + std::string serialized = opt->serialize(); + std::string key = opt_key; + std::map result = PrintConfigDef::from_prusa(key, serialized, global_config); + if (key != opt_key) { + conf.erase(opt_key); + } + if (!key.empty() && serialized != opt->serialize()) { + ConfigOption* opt_new = opt->clone(); + opt_new->deserialize(serialized); + conf.set_key_value(key, opt_new); + } + for (auto entry : result) { + const ConfigOptionDef* def = print_config_def.get(entry.first); + if (def) { + ConfigOption* opt_new = def->default_value.get()->clone(); + opt_new->deserialize(entry.second); + conf.set_key_value(entry.first, opt_new); + } + } + } + } + bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions) { mz_zip_archive archive; @@ -650,7 +680,7 @@ namespace Slic3r { // extract slic3r layer heights profile file _extract_layer_heights_profile_config_from_archive(archive, stat); } - if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) + if (boost::algorithm::iequals(name, SLIC3R_LAYER_CONFIG_RANGES_FILE)) { // extract slic3r layer config ranges file _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions); @@ -662,7 +692,7 @@ namespace Slic3r { { // extract sla support points file _extract_sla_drain_holes_from_archive(archive, stat); - } else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE)) + } else if (boost::algorithm::iequals(name, SLIC3R_PRINT_CONFIG_FILE)) { // extract slic3r print config file _extract_print_config_from_archive(archive, stat, config, config_substitutions, filename); @@ -672,7 +702,7 @@ namespace Slic3r { { // extract slic3r layer config ranges file _extract_custom_gcode_per_print_z_from_archive(archive, stat); - } else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE)) + } else if (boost::algorithm::iequals(name, SLIC3R_MODEL_CONFIG_FILE)) { // extract slic3r model config file if (!_extract_model_config_from_archive(archive, stat, model)) @@ -688,7 +718,7 @@ namespace Slic3r { //parsed superslicer/prusa files if slic3r not found //note that is we successfully read one of the config file, then the other ones should also have the same name auto read_from_other_storage = [this, &print_config_parsed, num_entries, &archive, &stat, &config, &model, &filename, &config_substitutions] - (const std::string &print_config_name, const std::string& model_config_name) -> bool { + (const std::string &print_config_name, const std::string& model_config_name, const std::string& layer_config_name, bool from_prusa) -> bool { for (mz_uint i = 0; i < num_entries; ++i) { if (mz_zip_reader_file_stat(&archive, i, &stat)) @@ -697,7 +727,12 @@ namespace Slic3r { std::replace(name.begin(), name.end(), '\\', '/'); //TODO use special methods to convert them better? - if (boost::algorithm::iequals(name, print_config_name)) + + if (boost::algorithm::iequals(name, layer_config_name)) + { + // extract slic3r layer config ranges file + _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions); + } else if (boost::algorithm::iequals(name, print_config_name)) { // extract slic3r print config file _extract_print_config_from_archive(archive, stat, config, config_substitutions, filename); @@ -717,15 +752,24 @@ namespace Slic3r { } return true; }; + bool use_prusa_config = false; if (!print_config_parsed) - if (!read_from_other_storage(PRINT_SUPER_CONFIG_FILE, MODEL_SUPER_CONFIG_FILE)) + if (!read_from_other_storage(SUPER_PRINT_CONFIG_FILE, SUPER_MODEL_CONFIG_FILE, SUPER_LAYER_CONFIG_RANGES_FILE, false)) return false; if (!print_config_parsed) - if (!read_from_other_storage(PRINT_PRUSA_CONFIG_FILE, MODEL_PRUSA_CONFIG_FILE)) + if (!read_from_other_storage(PRUSA_PRINT_CONFIG_FILE, PRUSA_MODEL_CONFIG_FILE, PRUSA_LAYER_CONFIG_RANGES_FILE, true)) return false; + else { + use_prusa_config = true; + convert_from_prusa(config, config); + } close_zip_reader(&archive); + for (auto range_config : m_layer_heights_profiles) { + + } + for (const IdToModelObjectMap::value_type& object : m_objects) { if (object.second >= m_model->objects.size()) { add_error("Unable to find object"); @@ -792,8 +836,18 @@ namespace Slic3r { volumes_ptr = &volumes; } + if (!_generate_volumes(*model_object, obj_geometry->second, *volumes_ptr, config_substitutions)) return false; + + if (use_prusa_config) { + convert_from_prusa(model_object->config, config); + for (ModelVolume* volume : model_object->volumes) + convert_from_prusa(volume->config, config); + for (auto entry : model_object->layer_config_ranges) + convert_from_prusa(entry.second, config); + } + } // // fixes the min z of the model if negative @@ -2105,7 +2159,7 @@ namespace Slic3r { bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets); bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items); bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model); - bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model); + bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig& global_config); bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, const std::string &file_path); @@ -2184,7 +2238,7 @@ namespace Slic3r { // Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt"). // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model. // The index differes from the index of an object ID of an object instance of a 3MF file! - if (!_add_layer_config_ranges_file_to_archive(archive, model)) + if (!_add_layer_config_ranges_file_to_archive(archive, model, *config)) { close_zip_writer(&archive); boost::filesystem::remove(filename); @@ -2223,9 +2277,9 @@ namespace Slic3r { if (config != nullptr) { // also add prusa (& superslicer for backward comp, just for some version from 2.3.56) print config - bool error = !_add_print_config_file_to_archive(archive, *config, PRINT_CONFIG_FILE); - error = error || !_add_print_config_file_to_archive(archive, *config, PRINT_PRUSA_CONFIG_FILE); - error = error || !_add_print_config_file_to_archive(archive, *config, PRINT_SUPER_CONFIG_FILE); + bool error = !_add_print_config_file_to_archive(archive, *config, SLIC3R_PRINT_CONFIG_FILE); + error = error || !_add_print_config_file_to_archive(archive, *config, PRUSA_PRINT_CONFIG_FILE); + error = error || !_add_print_config_file_to_archive(archive, *config, SUPER_PRINT_CONFIG_FILE); if(error) { close_zip_writer(&archive); @@ -2238,21 +2292,21 @@ namespace Slic3r { // This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides). // As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data // is stored here as well. - if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_CONFIG_FILE)) + if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, SLIC3R_MODEL_CONFIG_FILE)) { close_zip_writer(&archive); boost::filesystem::remove(filename); return false; } // also add prusa - if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_PRUSA_CONFIG_FILE)) + if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, PRUSA_MODEL_CONFIG_FILE)) { close_zip_writer(&archive); boost::filesystem::remove(filename); return false; } // also superslicer for backward comp, just for some version from 2.3.56 - if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_SUPER_CONFIG_FILE)) + if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, SUPER_MODEL_CONFIG_FILE)) { close_zip_writer(&archive); boost::filesystem::remove(filename); @@ -2598,61 +2652,85 @@ namespace Slic3r { return true; } - bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model) + bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig &globalConfig) { - std::string out = ""; - pt::ptree tree; + std::string default_out = ""; + std::string prusa_out = ""; - unsigned int object_cnt = 0; - for (const ModelObject* object : model.objects) - { - object_cnt++; - const t_layer_config_ranges& ranges = object->layer_config_ranges; - if (!ranges.empty()) + for (std::string* out : { &prusa_out , &default_out }) { + pt::ptree tree; + unsigned int object_cnt = 0; + for (const ModelObject* object : model.objects) { - pt::ptree& obj_tree = tree.add("objects.object",""); - - obj_tree.put(".id", object_cnt); - - // Store the layer config ranges. - for (const auto& range : ranges) + object_cnt++; + const t_layer_config_ranges& ranges = object->layer_config_ranges; + if (!ranges.empty()) { - pt::ptree& range_tree = obj_tree.add("range", ""); + pt::ptree& obj_tree = tree.add("objects.object", ""); - // store minX and maxZ - range_tree.put(".min_z", range.first.first); - range_tree.put(".max_z", range.first.second); + obj_tree.put(".id", object_cnt); - // store range configuration - const ModelConfig& config = range.second; - for (const std::string& opt_key : config.keys()) + // Store the layer config ranges. + for (const auto& range : ranges) { - pt::ptree& opt_tree = range_tree.add("option", config.opt_serialize(opt_key)); - opt_tree.put(".opt_key", opt_key); + pt::ptree& range_tree = obj_tree.add("range", ""); + + // store minX and maxZ + range_tree.put(".min_z", range.first.first); + range_tree.put(".max_z", range.first.second); + + // store range configuration + const ModelConfig& config = range.second; + for (const std::string& opt_key : config.keys()) + { + //check if we need to call 'to_prusa' to adapt config + if (out == &prusa_out) { + std::string value = config.opt_serialize(opt_key); + std::string key = opt_key; + PrintConfigDef::to_prusa(key, value, globalConfig); + if (!key.empty()) { + pt::ptree& opt_tree = range_tree.add("option", value); + opt_tree.put(".opt_key", opt_key); + } + } else { + pt::ptree& opt_tree = range_tree.add("option", config.opt_serialize(opt_key)); + opt_tree.put(".opt_key", opt_key); + } + } } } + + } + if (!tree.empty()) + { + std::ostringstream oss; + pt::write_xml(oss, tree); + *out = oss.str(); + + // Post processing("beautification") of the output string for a better preview + boost::replace_all(*out, ">\n \n \n ", ">\n "); + boost::replace_all(*out, ">", ">\n "); + // OR just + boost::replace_all(*out, "><", ">\n<"); } } - if (!tree.empty()) + if (!default_out.empty()) { - std::ostringstream oss; - pt::write_xml(oss, tree); - out = oss.str(); - - // Post processing("beautification") of the output string for a better preview - boost::replace_all(out, ">\n \n \n ", ">\n "); - boost::replace_all(out, ">", ">\n "); - // OR just - boost::replace_all(out, "><", ">\n<"); - } - - if (!out.empty()) - { - if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) + if (!mz_zip_writer_add_mem(&archive, SLIC3R_LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)default_out.data(), default_out.length(), MZ_DEFAULT_COMPRESSION)) + { + add_error("Unable to add layer heights profile file to archive"); + return false; + } + if (!mz_zip_writer_add_mem(&archive, SUPER_LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)default_out.data(), default_out.length(), MZ_DEFAULT_COMPRESSION)) + { + add_error("Unable to add layer heights profile file to archive"); + return false; + } + if (!mz_zip_writer_add_mem(&archive, PRUSA_LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)prusa_out.data(), prusa_out.length(), MZ_DEFAULT_COMPRESSION)) { add_error("Unable to add layer heights profile file to archive"); return false; @@ -2761,7 +2839,7 @@ namespace Slic3r { char buffer[1024]; sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str()); std::string out = buffer; - if (config_name == PRINT_PRUSA_CONFIG_FILE) { + if (config_name == PRUSA_PRINT_CONFIG_FILE) { for (std::string key : config.keys()) if (key != "compatible_printers") { std::string value = config.opt_serialize(key); @@ -2812,7 +2890,7 @@ namespace Slic3r { } // stores object's config data - if (file_path == MODEL_PRUSA_CONFIG_FILE) { + if (file_path == PRUSA_MODEL_CONFIG_FILE) { assert(obj->config.get().parent == nullptr); obj_config_wparent = obj->config.get(); obj_config_wparent.parent = &print_config; @@ -2887,7 +2965,7 @@ namespace Slic3r { } // stores volume's config data - if (file_path == MODEL_PRUSA_CONFIG_FILE) { + if (file_path == PRUSA_MODEL_CONFIG_FILE) { assert(volume->config.get().parent == nullptr); DynamicPrintConfig copy_config = volume->config.get(); copy_config.parent = &obj_config_wparent; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 66d7e54a3..c89152398 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5544,103 +5544,124 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } catch (boost::bad_lexical_cast &) { value = "0"; } - } else if (opt_key == "gcode_flavor" && value == "makerbot") { + } + if (opt_key == "gcode_flavor" && value == "makerbot") { value = "makerware"; - } else if (opt_key == "fill_density" && value.find("%") == std::string::npos) { + } + if (opt_key == "fill_density" && value.find("%") == std::string::npos) { try { // fill_density was turned into a percent value float v = boost::lexical_cast(value); value = boost::lexical_cast(v*100) + "%"; } catch (boost::bad_lexical_cast &) {} - } else if (opt_key == "randomize_start" && value == "1") { + } + if (opt_key == "randomize_start" && value == "1") { opt_key = "seam_position"; value = "random"; - } else if (opt_key == "bed_size" && !value.empty()) { + } + if (opt_key == "bed_size" && !value.empty()) { opt_key = "bed_shape"; ConfigOptionPoint p; p.deserialize(value, ForwardCompatibilitySubstitutionRule::Disable); std::ostringstream oss; oss << "0x0," << p.value(0) << "x0," << p.value(0) << "x" << p.value(1) << ",0x" << p.value(1); value = oss.str(); - } else if ((opt_key == "perimeter_acceleration" && value == "25") + } + if ((opt_key == "perimeter_acceleration" && value == "25") || (opt_key == "infill_acceleration" && value == "50")) { /* For historical reasons, the world's full of configs having these very low values; to avoid unexpected behavior we need to ignore them. Banning these two hard-coded values is a dirty hack and will need to be removed sometime in the future, but it will avoid lots of complaints for now. */ value = "0"; - } else if (opt_key == "support_material_pattern" && value == "pillars") { + } + if (opt_key == "support_material_pattern" && value == "pillars") { // Slic3r PE does not support the pillars. They never worked well. value = "rectilinear"; - } else if (opt_key == "skirt_height" && value == "-1") { + } + if (opt_key == "skirt_height" && value == "-1") { // PrusaSlicer no more accepts skirt_height == -1 to print a draft shield to the top of the highest object. // A new "draft_shield" boolean config value is used instead. opt_key = "draft_shield"; value = "1"; - } else if (opt_key == "octoprint_host") { + } + if (opt_key == "octoprint_host") { opt_key = "print_host"; - } else if (opt_key == "octoprint_cafile") { + } + if (opt_key == "octoprint_cafile") { opt_key = "printhost_cafile"; - } else if (opt_key == "octoprint_apikey") { + } + if (opt_key == "octoprint_apikey") { opt_key = "printhost_apikey"; - } else if (opt_key == "elefant_foot_compensation") { + } + if (opt_key == "elefant_foot_compensation") { opt_key = "first_layer_size_compensation"; float v = boost::lexical_cast(value); if (v > 0) value = boost::lexical_cast(-v); } - else if ("elefant_foot_min_width" == opt_key) { + if ("elefant_foot_min_width" == opt_key) { opt_key = "elephant_foot_min_width"; - } else if (opt_key == "thumbnails") { + } + if (opt_key == "thumbnails") { if (value.empty()) value = "0x0,0x0"; - } else if (opt_key == "z_steps_per_mm") { + } + if (opt_key == "z_steps_per_mm") { opt_key = "z_step"; float v = boost::lexical_cast(value); if(v > 0) value = boost::lexical_cast(1/v); - } else if (opt_key == "infill_not_connected") { + } + if (opt_key == "infill_not_connected") { opt_key = "infill_connection"; if (value == "1") value = "notconnected"; else value = "connected"; - } else if (opt_key == "seam_travel") { + } + if (opt_key == "seam_travel") { if (value == "1") { opt_key = "seam_travel_cost"; value = "200%"; } else { opt_key = ""; } - } else if (opt_key == "seam_position") { + } + if (opt_key == "seam_position") { if (value == "hidden") { opt_key = "seam_travel_cost"; value = "20%"; }else if ("near" == value || "nearest" == value ) value = "cost"; - } else if (opt_key == "perimeter_loop_seam") { + } + if (opt_key == "perimeter_loop_seam") { if (value == "hidden") { value = "nearest"; } - } else if (opt_key == "overhangs") { + } + if (opt_key == "overhangs") { opt_key = "overhangs_width_speed"; if (value == "1") value = "50%"; else value = "0"; - } else if (opt_key == "print_machine_envelope") { + } + if (opt_key == "print_machine_envelope") { opt_key = "machine_limits_usage"; if (value == "1") value = "emit_to_gcode"; else value = "time_estimate_only"; - } else if (opt_key == "retract_lift_not_last_layer") { + } + if (opt_key == "retract_lift_not_last_layer") { opt_key = "retract_lift_top"; if (value == "1") value = "Not on top"; else value = "All surfaces"; - } else if ("gcode_precision_e" == opt_key) { + } + if ("gcode_precision_e" == opt_key) { try { int val = boost::lexical_cast(value); if (val > 0) @@ -5692,6 +5713,20 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } } +//the map is for extra things to add / modify +std::map PrintConfigDef::from_prusa(t_config_option_key& opt_key, std::string& value, const DynamicConfig& all_conf) { + std::map output; + if ("toolchange_gcode" == opt_key) { + if (!value.empty() && value.find("T[next_extruder]") == std::string::npos) { + value = "T[next_extruder]\n" + value; + } + } + if ("xy_size_compensation" == opt_key) { + output["xy_inner_size_compensation"] = value; + } + return output; +} + std::unordered_set prusa_export_to_remove_keys = { "allow_empty_layers", "avoid_crossing_not_first_layer", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6914ba919..a9690d221 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -402,6 +402,7 @@ public: static void handle_legacy(t_config_option_key& opt_key, std::string& value); static void to_prusa(t_config_option_key& opt_key, std::string& value, const DynamicConfig& all_conf); + static std::map from_prusa(t_config_option_key& opt_key, std::string& value, const DynamicConfig& all_conf); // Array options growing with the number of extruders const std::vector& extruder_option_keys() const { return m_extruder_option_keys; }