diff --git a/CMakeLists.txt b/CMakeLists.txt index 58fd2b9..dfe2ff9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ set(IS_CROSS_COMPILE FALSE) set(FLATPAK FALSE CACHE BOOL "Not copy FFMPEG file") + if (APPLE) set(CMAKE_FIND_FRAMEWORK LAST) set(CMAKE_FIND_APPBUNDLE LAST) @@ -170,6 +171,14 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory. # We pick it from environment if it is not defined in another way if(WIN32) + if(EXISTS "${CMAKE_SOURCE_DIR}/scripts/hooks/pre-commit" AND EXISTS "${CMAKE_SOURCE_DIR}/.git") + message(STATUS ".git: directory") + configure_file( + "${CMAKE_SOURCE_DIR}/scripts/hooks/pre-commit" + "${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit" + ) + endif() + find_package(PkgConfig REQUIRED) if(NOT DEFINED WIN10SDK_PATH) if(DEFINED ENV{WIN10SDK_PATH}) @@ -366,7 +375,7 @@ endif() function(slic3r_remap_configs targets from_Cfg to_Cfg) if(MSVC) string(TOUPPER ${from_Cfg} from_CFG) - + foreach(tgt ${targets}) if(TARGET ${tgt}) set_target_properties(${tgt} PROPERTIES MAP_IMPORTED_CONFIG_${from_CFG} ${to_Cfg}) @@ -668,7 +677,7 @@ function(qidistudio_copy_dlls target config postfix output_dlls) ${_out_dir}/avutil-59.dll PARENT_SCOPE ) - + endfunction() function(qidistudio_copy_sos target config postfix output_sos) diff --git a/Dockerfile b/Dockerfile index 9c8d9c1..9220b28 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,8 +68,11 @@ WORKDIR /QIDIStudio # It might conflict with your mapped user, remove if user ubuntu exist RUN if id "ubuntu" >/dev/null 2>&1; then userdel -r ubuntu; fi - -# Use bash as the shell +# It's easier to run Bambu Studio as the same username, +# UID and GID as your workstation. Since we bind mount +# your home directory into the container, it's handy +# to keep permissions the same. Just in case, defaults +# are root. # Set ARG values # If user was passed from build it will create a user same @@ -114,11 +117,8 @@ RUN ./BuildLinux.sh -s ENV container=podman RUN ./BuildLinux.sh -i -# It's easier to run QIDI Studio as the same username, -# UID and GID as your workstation. Since we bind mount -# your home directory into the container, it's handy -# to keep permissions the same. Just in case, defaults -# are root. + +# Use bash as the shell SHELL ["/bin/bash", "-l", "-c"] # Point FFMPEG Library search to the binary built upon QIDIStudio build time diff --git a/src/QIDIStudio.cpp b/src/QIDIStudio.cpp index 1fc5bc8..0890822 100644 --- a/src/QIDIStudio.cpp +++ b/src/QIDIStudio.cpp @@ -438,7 +438,6 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config) void record_exit_reson(std::string outputdir, int code, int plate_id, std::string error_message, sliced_info_t& sliced_info, std::map key_values = std::map()) { -#if defined(__linux__) || defined(__LINUX__) std::string result_file; if (!outputdir.empty()) @@ -460,6 +459,14 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin j["error_string"] = error_message; j["prepare_time"] = sliced_info.prepare_time; j["export_time"] = sliced_info.export_time; + + if (code != 0) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ + << boost::format(" Slicer_Info_Report: plate_id=%1%, return_code=%2%, error_message=%3%\n") % plate_id % code % error_message; + + } + for (size_t index = 0; index < sliced_info.sliced_plates.size(); index++) { json plate_json; @@ -504,6 +511,7 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin } //filament info + double filament_usage_g = 0.0; if (!sliced_plate_info.filaments.empty()) { for (size_t j = 0; j < sliced_plate_info.filaments.size(); j++) @@ -515,13 +523,23 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin filament_json["filament_id"] = filament.filament_id; filament_json["total_used_g"] = filament.total_used_g; filament_json["main_used_g"] = filament.main_used_g; - + filament_usage_g += filament.total_used_g; plate_json["filaments"].push_back(std::move(filament_json)); } } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(" Slicer_Info_Report: plate_id=%1%, return_code=%2%, error_message=%3%, slice_time_s=%4%, pring_time_s=%5%, filament_usage_g=%6%\n") + % index + % code + % error_message + % (static_cast(sliced_plate_info.sliced_time) / 1000.0) + % sliced_plate_info.total_predication + % filament_usage_g; + j["sliced_plates"].push_back(std::move(plate_json)); } + + #if defined(__linux__) || defined(__LINUX__) for (auto& iter: key_values) j[iter.first] = iter.second; @@ -529,11 +547,10 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin c.open(result_file, std::ios::out | std::ios::trunc); c << std::setw(4) << j << std::endl; c.close(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%result_file; + #endif } catch (...) {} -#endif } static int decode_png_to_thumbnail(std::string png_file, ThumbnailData& thumbnail_data) @@ -1297,6 +1314,27 @@ static void load_downward_settings_list_from_config(std::string config_file, std } } +//y66 +std::string normalizeString(const std::string& str) { + std::string result; + for (char ch : str) { + if (std::isalnum(ch) || ch == '.') { + result += std::tolower(ch); + } + } + return result; +} + +//y66 +bool containsSubstring(const std::string& str, const std::string& substr) { + std::string norm_str = normalizeString(str); + std::string norm_substr = normalizeString(substr); + if (norm_str.find(norm_substr) != std::string::npos) { + return true; + } + return false; +} + int CLI::run(int argc, char **argv) { // Mark the main thread for the debugger and for runtime checks. @@ -1381,6 +1419,7 @@ int CLI::run(int argc, char **argv) boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); #endif // _WIN32*/ + bool translate_old = false, regenerate_thumbnails = false, keep_old_params = false, filament_color_changed = false, downward_check = false; int current_printable_width, current_printable_depth, current_printable_height, shrink_to_new_bed = 0; int old_printable_height = 0, old_printable_width = 0, old_printable_depth = 0; @@ -1388,7 +1427,7 @@ int CLI::run(int argc, char **argv) float old_max_radius = 0.f, old_height_to_rod = 0.f, old_height_to_lid = 0.f, old_filament_prime_volume = 0.f; std::vector old_max_layer_height, old_min_layer_height; std::string outfile_dir = m_config.opt_string("outputdir", true); - const std::vector &load_configs = m_config.option("load_settings", true)->values; + std::vector &load_configs = m_config.option("load_settings", true)->values; const std::vector &uptodate_configs = m_config.option("uptodate_settings", true)->values; const std::vector &uptodate_filaments = m_config.option("uptodate_filaments", true)->values; std::vector downward_settings = m_config.option("downward_settings", true)->values; @@ -1397,7 +1436,7 @@ int CLI::run(int argc, char **argv) //QDS: always use ForwardCompatibilitySubstitutionRule::Enable //const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; const ForwardCompatibilitySubstitutionRule config_substitution_rule = ForwardCompatibilitySubstitutionRule::Enable; - const std::vector &load_filaments = m_config.option("load_filaments", true)->values; + std::vector &load_filaments = m_config.option("load_filaments", true)->values; //skip model object logic const std::vector &skip_objects = m_config.option("skip_objects", true)->values; std::map skip_maps; @@ -1410,6 +1449,168 @@ int CLI::run(int argc, char **argv) if (downward_check_option) downward_check = downward_check_option->value; + +#if 0 + //y66 + std::vector temp_paths; + std::string default_serices = "X 4 Series"; + std::string default_machine_type = "X-Plus 4"; + std::string default_nozzle_type = "0.4"; + std::string default_filament_type = "QIDI PLA Rapido"; + std::string default_print_quality = "0.20mm Standard"; + std::string target_path = ""; + + { + std::string machine_path_base = resources_dir() + "\\profiles\\" + default_serices + "\\machine"; + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + std::string filename = entry.path().filename().string(); + if (containsSubstring(filename, default_machine_type) && containsSubstring(filename, default_nozzle_type)) { + target_path = entry.path().string(); + break; + } + } + + DynamicPrintConfig config; + ConfigSubstitutions config_substitutions; + std::map key_values; + std::string reason; + config_substitutions = config.load_from_json(target_path, config_substitution_rule, key_values, reason); + std::string inherits = ""; + if (config.has("inherits")) { + std::string new_inherits = config.opt_string("inherits"); + while (inherits != new_inherits) { + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + std::string filename = entry.path().filename().string(); + if (containsSubstring(filename, new_inherits)) { + target_path = entry.path().string(); + break; + } + } + DynamicPrintConfig new_config; + config_substitutions = new_config.load_from_json(target_path, config_substitution_rule, key_values, reason); + inherits = new_inherits; + if (new_config.has("inherits")) { + new_inherits = new_config.opt_string("inherits"); + } + t_config_option_keys& new_config_keys = new_config.keys(); + for (auto key : new_config_keys) { + if (!config.has(key)) { + ConfigOption* dest_opt = config.option(key, true); + dest_opt->set(new_config.option(key)); + } + } + config.set_key_value("inherits", new ConfigOptionString(new_inherits)); + } + } + std::string store_path = resources_dir() + "\\profiles\\temp_machine.json"; + config.save_to_temp_json(store_path, key_values); + load_configs.emplace_back(store_path); + temp_paths.emplace_back(store_path); + } + + + { + std::string machine_path_base = resources_dir() + "\\profiles\\" + default_serices + "\\process"; + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + std::string filename = entry.path().filename().string(); + if (containsSubstring(filename, default_print_quality) && containsSubstring(filename, default_machine_type)) { + target_path = entry.path().string(); + break; + } + } + + DynamicPrintConfig config; + ConfigSubstitutions config_substitutions; + std::map key_values; + std::string reason; + config_substitutions = config.load_from_json(target_path, config_substitution_rule, key_values, reason); + std::string inherits = ""; + if (config.has("inherits")) { + std::string new_inherits = config.opt_string("inherits"); + while (inherits != new_inherits) { + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + std::string filename = entry.path().filename().string(); + if (containsSubstring(filename, new_inherits)) { + target_path = entry.path().string(); + break; + } + } + DynamicPrintConfig new_config; + config_substitutions = new_config.load_from_json(target_path, config_substitution_rule, key_values, reason); + inherits = new_inherits; + if (new_config.has("inherits")) { + new_inherits = new_config.opt_string("inherits"); + } + t_config_option_keys& new_config_keys = new_config.keys(); + for (auto key : new_config_keys) { + if (!config.has(key)) { + ConfigOption* dest_opt = config.option(key, true); + dest_opt->set(new_config.option(key)); + } + } + config.set_key_value("inherits", new ConfigOptionString(new_inherits)); + } + } + std::string store_path = resources_dir() + "\\profiles\\temp_process.json"; + config.save_to_temp_json(store_path, key_values); + load_configs.emplace_back(store_path); + temp_paths.emplace_back(store_path); + } + + { + std::string machine_path_base = resources_dir() + "\\profiles\\" + default_serices + "\\filament"; + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + std::string filename = entry.path().filename().string(); + std::string target_filename = default_filament_type + " @Qidi" + default_machine_type + " " + default_nozzle_type; + if (containsSubstring(filename, target_filename)) { + target_path = entry.path().string(); + break; + } + } + + DynamicPrintConfig config; + ConfigSubstitutions config_substitutions; + std::map key_values; + std::string reason; + config_substitutions = config.load_from_json(target_path, config_substitution_rule, key_values, reason); + std::string inherits = ""; + if (config.has("inherits")) { + std::string new_inherits = config.opt_string("inherits"); + while (inherits != new_inherits) { + for (const auto& entry : fs::directory_iterator(machine_path_base)) { + DynamicPrintConfig temp_config; + std::map temp_key_values; + std::string temp_reason; + config_substitutions = temp_config.load_from_json(entry.path().string(), config_substitution_rule, temp_key_values, temp_reason); + if (containsSubstring(temp_key_values["name"], new_inherits)) { + target_path = entry.path().string(); + break; + } + } + + DynamicPrintConfig new_config; + config_substitutions = new_config.load_from_json(target_path, config_substitution_rule, key_values, reason); + inherits = new_inherits; + if (new_config.has("inherits")) { + new_inherits = new_config.opt_string("inherits"); + } + t_config_option_keys& new_config_keys = new_config.keys(); + for (auto key : new_config_keys) { + if (!config.has(key)) { + ConfigOption* dest_opt = config.option(key, true); + dest_opt->set(new_config.option(key)); + } + } + config.set_key_value("inherits", new ConfigOptionString(new_inherits)); + } + } + std::string store_path = resources_dir() + "\\profiles\\temp_filament.json"; + config.save_to_temp_json(store_path, key_values); + load_filaments.emplace_back(store_path); + temp_paths.emplace_back(store_path); + } +#endif + bool start_gui = m_actions.empty() && !downward_check; if (start_gui) { BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl; @@ -1485,6 +1686,7 @@ int CLI::run(int argc, char **argv) bool first_file = true, is_qdt_3mf = false, need_arrange = true, has_thumbnails = false, up_config_to_date = false, normative_check = true, duplicate_single_object = false, use_first_fila_as_default = false, minimum_save = false, enable_timelapse = false; bool allow_rotations = true, skip_modified_gcodes = false, avoid_extrusion_cali_region = false, skip_useless_pick = false, allow_newer_file = false, current_is_multi_extruder = false, new_is_multi_extruder = false, allow_mix_temp = false; Semver file_version; + Slic3r::GUI::Camera::ViewAngleType camera_view = Slic3r::GUI::Camera::ViewAngleType::Iso; std::map orients_requirement; std::vector project_presets; std::string new_printer_name, current_printer_name, new_process_name, current_process_name, current_printer_system_name, current_process_system_name, new_process_system_name, new_printer_system_name, printer_model_id, current_printer_model, printer_model, new_default_process_name; @@ -1549,6 +1751,10 @@ int CLI::run(int argc, char **argv) if (allow_mix_temp_option) allow_mix_temp = allow_mix_temp_option->value; + ConfigOptionInt* camera_view_option = m_config.option("camera_view"); + if (camera_view_option) + camera_view = (Slic3r::GUI::Camera::ViewAngleType)(camera_view_option->value); + ConfigOptionBool* avoid_extrusion_cali_region_option = m_config.option("avoid_extrusion_cali_region"); if (avoid_extrusion_cali_region_option) avoid_extrusion_cali_region = avoid_extrusion_cali_region_option->value; @@ -2133,6 +2339,7 @@ int CLI::run(int argc, char **argv) if (!is_qdt_3mf && config.option("different_settings_to_system")) { std::vector diff_settings = config.option("different_settings_to_system")->values; different_process_setting = diff_settings[0]; + config.erase("different_settings_to_system"); } load_process_config = std::move(config); BOOST_LOG_TRIVIAL(info) << boost::format("loaded process config %1%, type %2%, name %3%, inherits %4%")%file %config_name %config_from % new_process_system_name; @@ -2946,7 +3153,7 @@ int CLI::run(int argc, char **argv) } else { //todo: support system process preset - different_settings[0] = ""; + different_settings[0] = different_process_setting; if (new_process_config_is_system) inherits_group[0] = ""; else @@ -3087,7 +3294,17 @@ int CLI::run(int argc, char **argv) config.erase("filament_settings_id"); //todo: update different settings of filaments - different_settings[filament_index] = ""; + if (config.option("different_settings_to_system")) { + std::vector filament_different_settings = config.option("different_settings_to_system", true)->values; + if (filament_different_settings.empty()) + different_settings[filament_index] = ""; + else + different_settings[filament_index] = filament_different_settings[0]; + config.erase("different_settings_to_system"); + } + else { + different_settings[filament_index] = ""; + } inherits_group[filament_index] = load_filaments_inherit[index]; } else { @@ -3775,7 +3992,10 @@ int CLI::run(int argc, char **argv) ConfigOptionFloat* brim_width_option = print_config.option("prime_tower_brim_width", true); float brim_width = brim_width_option->value; - if (brim_width < 0) brim_width = WipeTower::get_auto_brim_by_height((float)plate_obj_size_info.obj_bbox.max.z()); + if (brim_width < 0) + brim_width = WipeTower::get_auto_brim_by_height((float)plate_obj_size_info.obj_bbox.max.z()); + //if (brim_width < WIPE_TOWER_MARGIN) + // brim_width = WIPE_TOWER_MARGIN; ConfigOptionFloats* volume_option = print_config.option("filament_prime_volume", true); std::vector wipe_volume = volume_option->values; @@ -3785,9 +4005,9 @@ int CLI::run(int argc, char **argv) plate_obj_size_info.wipe_depth = wipe_tower_size(1); Vec3d origin = plate->get_origin(); - Vec3d start(origin(0) + plate_obj_size_info.wipe_x - brim_width, origin(1) + plate_obj_size_info.wipe_y, 0.f); + Vec3d start(origin(0) + plate_obj_size_info.wipe_x - brim_width, origin(1) + plate_obj_size_info.wipe_y - brim_width, 0.f); plate_obj_size_info.obj_bbox.merge(start); - Vec3d end(origin(0) + plate_obj_size_info.wipe_x + plate_obj_size_info.wipe_width + brim_width, origin(1) + plate_obj_size_info.wipe_y + plate_obj_size_info.wipe_depth, 0.f); + Vec3d end(origin(0) + plate_obj_size_info.wipe_x + plate_obj_size_info.wipe_width + brim_width, origin(1) + plate_obj_size_info.wipe_y + plate_obj_size_info.wipe_depth + brim_width, 0.f); plate_obj_size_info.obj_bbox.merge(end); plate_obj_size_info.has_wipe_tower = true; BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, has wipe tower, wipe bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}") @@ -4386,6 +4606,10 @@ int CLI::run(int argc, char **argv) if (orients_requirement[o->id().id]) { BOOST_LOG_TRIVIAL(info) << "Before process command, Orient object, name=" << o->name <<",id="<id().id<config.assign_config(load_process_config); + } orientation::orient(o); oriented_or_arranged = true; } @@ -5322,11 +5546,12 @@ int CLI::run(int argc, char **argv) // loop through action options bool export_to_3mf = false, load_slicedata = false, export_slicedata = false, export_slicedata_error = false; + bool export_to_gcode = false; bool no_check = false; - std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir, export_stls_dir; + std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir, export_stls_dir, export_gcode_file; std::vector calibration_thumbnails; std::vector plate_object_count(partplate_list.get_plate_count(), 0); - int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0, sliced_plate = -1; + int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0, sliced_plate = -1, export_png = -1; std::vector plate_has_skips(partplate_list.get_plate_count(), false); std::vector> plate_skipped_objects(partplate_list.get_plate_count()); @@ -5538,9 +5763,21 @@ int CLI::run(int argc, char **argv) } */else if (opt_key == "export_3mf") { export_to_3mf = true; export_3mf_file = m_config.opt_string(opt_key); - }else if(opt_key=="no_check"){ + } + else if (opt_key == "export_png") { + export_png = m_config.option("export_png")->value; + if (m_actions.size() > 1) { + BOOST_LOG_TRIVIAL(error) << "should not set export_png with other actions together." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + } + else if(opt_key=="no_check"){ no_check = m_config.opt_bool(opt_key); //} else if (opt_key == "export_gcode" || opt_key == "export_sla" || opt_key == "slice") { + }else if(opt_key == "export_gcode"){ + export_to_gcode = true; + export_gcode_file = m_config.opt_string(opt_key); } else if (opt_key == "normative_check") { //already processed before } else if (opt_key == "export_slicedata") { @@ -5820,17 +6057,6 @@ int CLI::run(int argc, char **argv) else filament_maps = part_plate->get_real_filament_maps(m_print_config); - std::vector& unprintable_filament_types = m_print_config.option("unprintable_filament_types", true)->values; - std::vector>unprintable_filament_type_list; - unprintable_filament_type_list.resize(new_extruder_count); - for (int index = 0; index < new_extruder_count; index++) - { - std::vector unprintable_list; - if (unprintable_filament_types.size() > index) - unprintable_list = split_string(unprintable_filament_types[index], ','); - unprintable_filament_type_list[index] = unprintable_list; - } - for (int index = 0; index < filament_maps.size(); index++) { int filament_extruder = filament_maps[index]; @@ -5843,18 +6069,23 @@ int CLI::run(int argc, char **argv) } for (int f_index = 0; f_index < plate_filaments.size(); f_index++) { - if (plate_filaments[f_index] <= filament_count) { - int filament_extruder = filament_maps[plate_filaments[f_index] - 1]; - std::vector& unprintable_list = unprintable_filament_type_list[filament_extruder-1]; - std::string filament_type; - m_print_config.get_filament_type(filament_type, plate_filaments[f_index]-1); - if (unprintable_list.size() > 0) - { - auto iter = std::find(unprintable_list.begin(), unprintable_list.end(), filament_type); - if (iter != unprintable_list.end()) { - BOOST_LOG_TRIVIAL(error) << boost::format("plate %1% : filament %2% can not be printed on extruder %3%, under manual mode for multi extruder printer") % (index + 1) %filament_type %filament_extruder; - record_exit_reson(outfile_dir, CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER, index + 1, cli_errors[CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER], sliced_info); - flush_and_exit(CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER); + for (int f_index = 0; f_index < plate_filaments.size(); f_index++) { + if (plate_filaments[f_index] <= filament_count) { + int filament_extruder = filament_maps[plate_filaments[f_index] - 1]; + std::string filament_type; + m_print_config.get_filament_type(filament_type, plate_filaments[f_index] - 1); + auto *filament_printable_status = dynamic_cast(m_print_config.option("filament_printable")); + if (filament_printable_status && (filament_printable_status->values.size() >= plate_filaments[f_index])) { + int status = filament_printable_status->values.at(plate_filaments[f_index] - 1); + if (!(status >> (filament_extruder - 1) & 1)) { + BOOST_LOG_TRIVIAL(error) + << boost::format( + "plate %1% : filament %2% can not be printed on extruder %3%, under manual mode for multi extruder printer") % + (index + 1) % filament_type % filament_extruder; + record_exit_reson(outfile_dir, CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER, index + 1, + cli_errors[CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER], sliced_info); + flush_and_exit(CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER); + } } } } @@ -7011,6 +7242,62 @@ int CLI::run(int argc, char **argv) for (int i = 0; i < plate_bboxes.size(); i++) delete plate_bboxes[i]; } + else if (export_png >= 0) + { + std::vector thumbnails; + PlateDataPtrs plate_data_list; + partplate_list.store_to_3mf_structure(plate_data_list); + if (!opengl_valid) + opengl_valid = init_opengl_and_colors(m_models[0], colors); + + if (opengl_valid) { + Model& model = m_models[0]; + p_opengl_mgr->bind_vao(); + p_opengl_mgr->bind_shader(shader); + for (int i = 0; i < partplate_list.get_plate_count(); i++) { + Slic3r::GUI::PartPlate* part_plate = partplate_list.get_plate(i); + PlateData* plate_data = plate_data_list[i]; + ThumbnailData* thumbnail_data = &plate_data->plate_thumbnail; + + if ((export_png != 0) && (export_png != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: export png, Skip plate %2%.") % __LINE__ % (i + 1); + } + else { + unsigned int thumbnail_width = 512, thumbnail_height = 512; + const ThumbnailsParams thumbnail_params = { {}, false, true, true, true, i }; + + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s png, need to generate") % (i + 1); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(p_opengl_mgr, *thumbnail_data, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, camera_view); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s png,finished rendering") % (i + 1); + + std::string pnf_file = "plate_" + std::to_string(i + 1) + "_" + std::to_string((int)camera_view)+".png"; + if (!outfile_dir.empty()) { + pnf_file = outfile_dir + "/" + pnf_file; + } + bool write_result = Slic3r::png::write_gl_rgba_to_file(pnf_file.c_str(), thumbnail_width, thumbnail_height, (const uint8_t*)thumbnail_data->pixels.data()); + if (write_result) + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s png write to %2% success") % (i + 1) % pnf_file; + else { + BOOST_LOG_TRIVIAL(error) << boost::format("plate %1%'s png write to %2% failed") % (i + 1) % pnf_file; + record_exit_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR], sliced_info); + flush_and_exit(CLI_EXPORT_3MF_ERROR); + } + } + } + p_opengl_mgr->unbind_shader(); + p_opengl_mgr->unbind_vao(); + } + } + + if(export_to_gcode){ + for (int index = 0; index < partplate_list.get_plate_count(); index ++){ + Slic3r::GUI::PartPlate* part_plate = partplate_list.get_plate(index); + std::string temp_gcode = part_plate->get_tmp_gcode_path(); + fs::copy_file(temp_gcode, export_gcode_file, fs::copy_options::overwrite_existing); + } + } if (plate_data_src.size() > 0) { @@ -7055,6 +7342,14 @@ int CLI::run(int argc, char **argv) boost::nowide::cout.flush(); boost::nowide::cerr.flush(); +#if 0 + if(temp_paths.empty()){ + for(auto temp_path : temp_paths){ + fs::remove(temp_path); + } + } +#endif + return 0; } diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 7a3ce3a..0ed0f88 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -639,7 +639,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p SVG svg(debug_out_path("machine_boarder.svg"), m_object->bounding_box()); if (svg.is_opened()) svg.draw(m_machine_border, "yellow"); #endif -BOOST_LOG_TRIVIAL(debug) << "tree support construct finish"; + BOOST_LOG_TRIVIAL(debug) << "tree support construct finish"; } void add_overhang(Layer *layer, const ExPolygon &overhang, int type) @@ -1142,6 +1142,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) } } + for (auto &cluster : overhangClusters) { bool enforce_add = false; // remove small overhangs @@ -1527,7 +1528,7 @@ void TreeSupport::generate_toolpaths() const Layer *layer = m_object->layers().front(); for (const ExPolygon &expoly : layer->lslices) { raft_areas.push_back(expoly); - } + } } if (m_object->support_layer_count() > m_raft_layers) { @@ -1621,7 +1622,6 @@ void TreeSupport::generate_toolpaths() if (m_object->support_layer_count() <= m_raft_layers) return; - // generate tree support tool paths tbb::parallel_for( tbb::blocked_range(m_raft_layers, m_object->support_layer_count()), @@ -1893,7 +1893,7 @@ void TreeSupport::generate() generate_tree_support_3D(*m_object, this, this->throw_on_cancel); return; } - + profiler.stage_start(STAGE_total); // Generate overhang areas @@ -2381,7 +2381,7 @@ void TreeSupport::draw_circles() if (obj_layer_nr>0 && node.distance_to_top < 0) append(roof_gap_areas, area); else if (m_support_params.num_top_interface_layers > 0 && obj_layer_nr > 0 && (node.support_roof_layers_below == 0 || node.support_roof_layers_below == 1) && - node.distance_to_top >= m_support_params.num_top_interface_layers) { + node.distance_to_top >= m_support_params.num_top_interface_layers) { append(roof_1st_layer, area); max_layers_above_roof1 = std::max(max_layers_above_roof1, node.dist_mm_to_top); } @@ -2540,7 +2540,7 @@ void TreeSupport::draw_circles() contours.emplace_back(to_polygons(base_areas_lower)); printZ_to_lightninglayer[lower_layer->print_z] = overhangs.size() - 1; - #ifdef SUPPORT_TREE_DEBUG_TO_SVG +#ifdef SUPPORT_TREE_DEBUG_TO_SVG if (!overhang.empty() && !base_areas_lower.empty()) { std::string fname = debug_out_path("lightning_%d_%.2f.svg", layer_nr, ts_layer->print_z); SVG::export_expolygons(fname, {{base_areas_lower, {"base_areas_lower", "red", 0.5}}, {overhang, {"overhang", "blue", 0.5}}}); @@ -3251,7 +3251,7 @@ void TreeSupport::drop_nodes() #endif coordf_t next_radius = calc_radius(node.dist_mm_to_top + height_next); auto avoidance_next = get_avoidance(next_radius, obj_layer_nr_next); - + Point to_outside = projection_onto(avoidance_next, node.position); Point direction_to_outer = to_outside - node.position; if (node.skin_direction != Point(0, 0) && node.dist_mm_to_top < 3) { @@ -3267,7 +3267,7 @@ void TreeSupport::drop_nodes() Point candidate_vertex = node.position; const coordf_t max_move_between_samples = max_move_distance + radius_sample_resolution + EPSILON; // 100 micron extra for rounding errors. // use get_collision instead of get_avoidance here (See STUDIO-4252) - bool is_outside = move_out_expolys(get_collision(next_radius,layer_nr_next), candidate_vertex, max_move_between_samples, max_move_between_samples); + bool is_outside = move_out_expolys(get_collision(next_radius,obj_layer_nr_next), candidate_vertex, max_move_between_samples, max_move_between_samples); if (is_outside) { direction_to_outer = candidate_vertex - node.position; dist2_to_outer = vsize2_with_unscale(direction_to_outer); @@ -3836,7 +3836,7 @@ void TreeSupport::generate_contact_points() added = true; }; return contact_node; - }; + }; for (const auto& overhang_with_type : layer->loverhangs_with_type) { const auto &overhang_part = overhang_with_type.first; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 4aa63db..508c56c 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -258,6 +258,23 @@ int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp) { + //y65 + // try { + // auto putFile = reinterpret_cast*>(userp); + // if (!putFile) { throw std::runtime_error(std::string("The unique_ptr is nullptr! please check")); return CURL_READFUNC_ABORT; } + + // fs::ifstream* fstream = putFile->get(); + // if (!fstream) { throw std::runtime_error(std::string("The fstream is nullptr! please check")); return CURL_READFUNC_ABORT; } + + + // fstream->read(buffer, size * nitems); + // return fstream->gcount(); + // } catch (const std::exception &) { + // return CURL_READFUNC_ABORT; + // } + + // return CURL_READFUNC_ABORT; + auto stream = reinterpret_cast(userp); try {