From 9b19dc9eddc4c5887bc747ac2d913231571e57f0 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Thu, 9 May 2024 09:39:14 +0800 Subject: [PATCH] ENH: CLI: add logic for backward compatible check 1. add logic for backward compatible check 2. add export_stls JIRA: no-jira Change-Id: If96ab225b9689e588fae7443e81a73d0872f7eb4 (cherry picked from commit db12cca05c8f60fdc717387253215e361ab29851) --- src/BambuStudio.cpp | 568 ++++++++++++++++++++++++---------- src/BambuStudio.hpp | 26 +- src/libslic3r/PrintConfig.cpp | 13 +- src/slic3r/GUI/PartPlate.cpp | 22 ++ src/slic3r/GUI/PartPlate.hpp | 1 + 5 files changed, 465 insertions(+), 165 deletions(-) diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 5f012d4f8..7f6da8839 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -161,6 +161,8 @@ typedef struct _sliced_info { std::vector sliced_plates; size_t prepare_time; size_t export_time; + std::vector upward_machines; + std::vector downward_machines; }sliced_info_t; std::vector g_slicing_warnings; @@ -409,6 +411,10 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin try { json j; //record the headers + if (sliced_info.downward_machines.size() > 0) + j["downward_compatible_machine"] = sliced_info.downward_machines; + if (sliced_info.upward_machines.size() > 0) + j["upward_compatible_machine"] = sliced_info.upward_machines; j["plate_index"] = plate_id; j["return_code"] = code; j["error_string"] = error_message; @@ -979,8 +985,6 @@ int CLI::run(int argc, char **argv) PrinterTechnology printer_technology = get_printer_technology(m_config); - bool start_gui = m_actions.empty(); - //BBS: remove GCodeViewer as seperate APP logic /*bool start_as_gcodeviewer = #ifdef _WIN32 @@ -990,8 +994,8 @@ 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, shrink_to_new_bed = false, filament_color_changed = false; - int current_printable_width, current_printable_depth, current_printable_height; + bool translate_old = false, regenerate_thumbnails = false, filament_color_changed = 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; Pointfs old_printable_area, old_exclude_area; float old_max_radius = 0.f, old_height_to_rod = 0.f, old_height_to_lid = 0.f; @@ -1000,6 +1004,8 @@ int CLI::run(int argc, char **argv) const 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; + const std::vector &downward_check = m_config.option("downward_check", true)->values; + std::vector downward_compatible_machines; //BBS: always use ForwardCompatibilitySubstitutionRule::Enable //const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; const ForwardCompatibilitySubstitutionRule config_substitution_rule = ForwardCompatibilitySubstitutionRule::Enable; @@ -1012,6 +1018,7 @@ int CLI::run(int argc, char **argv) sliced_info_t sliced_info; std::map record_key_values; + bool start_gui = m_actions.empty() && downward_check.empty(); if (start_gui) { BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl; ::Label::initSysFont(); @@ -1080,6 +1087,7 @@ int CLI::run(int argc, char **argv) //BBS: add plate data related logic PlateDataPtrs plate_data_src; + std::vector plate_obj_size_infos; int arrange_option; int plate_to_slice = 0, filament_count = 0, duplicate_count = 0, real_duplicate_count = 0; bool first_file = true, is_bbl_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; @@ -2100,7 +2108,7 @@ int CLI::run(int argc, char **argv) } //upwards check - bool process_compatible = false, machine_upwards = false; + bool process_compatible = false, machine_upwards = false, machine_switch = false; BOOST_LOG_TRIVIAL(info) << boost::format("current printer %1%, new printer %2%, current process %3%, new process %4%")%current_printer_name %new_printer_name %current_process_name %new_process_name; BOOST_LOG_TRIVIAL(info) << boost::format("current printer inherits %1%, new printer inherits %2%, current process inherits %3%, new process inherits %4%") %current_printer_system_name %new_printer_system_name %current_process_system_name %new_process_system_name; @@ -2162,11 +2170,16 @@ int CLI::run(int argc, char **argv) %current_printer_name %current_printer_system_name %current_process_name %current_process_system_name %process_compatible; } if (!process_compatible && !new_printer_name.empty() && !current_printer_name.empty() && (new_printer_name != current_printer_name)) { + //set all printer to compatible + process_compatible = true; + machine_switch = true; + BOOST_LOG_TRIVIAL(info) << boost::format("switch to new printers, set to compatible"); if (upward_compatible_printers.size() > 0) { for (int index = 0; index < upward_compatible_printers.size(); index++) { if (upward_compatible_printers[index] == new_printer_system_name) { process_compatible = true; machine_upwards = true; + BOOST_LOG_TRIVIAL(info) << boost::format("new printer is upward_compatible"); break; } } @@ -2176,11 +2189,11 @@ int CLI::run(int argc, char **argv) flush_and_exit(CLI_3MF_NEW_MACHINE_NOT_SUPPORTED); } } - else { + /*else { BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1%: current 3mf file not support upward_compatible_printers, can not change machine preset.")%__LINE__; record_exit_reson(outfile_dir, CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE, 0, cli_errors[CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE], sliced_info); flush_and_exit(CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE); - } + }*/ } if (!process_compatible) { @@ -2188,10 +2201,11 @@ int CLI::run(int argc, char **argv) record_exit_reson(outfile_dir, CLI_PROCESS_NOT_COMPATIBLE, 0, cli_errors[CLI_PROCESS_NOT_COMPATIBLE], sliced_info); flush_and_exit(CLI_PROCESS_NOT_COMPATIBLE); } + sliced_info.upward_machines = upward_compatible_printers; //create project embedded preset if needed Preset *new_preset = NULL; - if (is_bbl_3mf && machine_upwards) { + if (is_bbl_3mf && machine_switch) { //we need to update the compatible printer and create a new process here, or if we load the 3mf in studio, the process preset can not be loaded as not compatible Preset *current_preset = NULL; size_t project_presets_count = project_presets.size(); @@ -2467,7 +2481,7 @@ int CLI::run(int argc, char **argv) } } - if (machine_upwards) { + if (machine_switch) { print_compatible_printers.push_back(new_printer_system_name); std::string old_setting = different_settings[0]; @@ -2852,134 +2866,6 @@ int CLI::run(int argc, char **argv) flush_and_exit(CLI_INVALID_VALUES_IN_3MF); } - //BBS: partplate list - Slic3r::GUI::PartPlateList partplate_list(NULL, m_models.data(), printer_technology); - //use Pointfs insteadof Points - Pointfs current_printable_area = m_print_config.opt("printable_area")->values; - Pointfs current_exclude_area = m_print_config.opt("bed_exclude_area")->values; - //update part plate's size - double print_height = m_print_config.opt_float("printable_height"); - double height_to_lid = m_print_config.opt_float("extruder_clearance_height_to_lid"); - double height_to_rod = m_print_config.opt_float("extruder_clearance_height_to_rod"); - double cleareance_radius = m_print_config.opt_float("extruder_clearance_max_radius"); - //double plate_stride; - std::string bed_texture; - - current_printable_width = current_printable_area[2].x() - current_printable_area[0].x(); - current_printable_depth = current_printable_area[2].y() - current_printable_area[0].y(); - current_printable_height = print_height; - if (old_printable_width == 0) - old_printable_width = current_printable_width; - if (old_printable_depth == 0) - old_printable_depth = current_printable_depth; - if (old_printable_height == 0) - old_printable_height = current_printable_height; - if ((old_printable_width > 0)&&(old_printable_depth > 0)&&(old_printable_height > 0)) - { - //check the printable size logic - //if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth) || (old_printable_height > current_printable_height)) - if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth)) - { - BOOST_LOG_TRIVIAL(error) << boost::format("old printable size {%1%, %2%, %3%} is larger than new printable size {%4%, %5%, %6%}, can not print") - %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; - record_exit_reson(outfile_dir, CLI_PRINTABLE_SIZE_REDUCED, 0, cli_errors[CLI_PRINTABLE_SIZE_REDUCED], sliced_info); - flush_and_exit(CLI_PRINTABLE_SIZE_REDUCED); - } - else if ((old_printable_width < current_printable_width) || (old_printable_depth < current_printable_depth)) - { - BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%} is smaller than new printable size {%4%, %5%, %6%}, need to center the model") - %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; - shrink_to_new_bed = true; - } - else { - BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}") - %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; - } - } - - if (m_models.size() > 0) - { - BOOST_LOG_TRIVIAL(info) << boost::format("translate_old %1%, shrink_to_new_bed %2%, old bed size {%3%, %4%, %5%}")%translate_old%shrink_to_new_bed %old_printable_width %old_printable_depth %old_printable_height; - if (translate_old) { - BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch to older bed size,{%1%, %2%, %3%}")%(old_printable_width + bed3d_ax3s_default_tip_radius)%(old_printable_depth+bed3d_ax3s_default_tip_radius) %old_printable_height; - partplate_list.reset_size(old_printable_width + bed3d_ax3s_default_tip_radius, old_printable_depth + bed3d_ax3s_default_tip_radius, old_printable_height, false); - } - else { - partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false); - } - partplate_list.set_shapes(current_printable_area, current_exclude_area, bed_texture, height_to_lid, height_to_rod); - //plate_stride = partplate_list.plate_stride_x(); - } - - auto translate_models = [translate_old, shrink_to_new_bed, old_printable_width, old_printable_depth, old_printable_height, current_printable_width, current_printable_depth, current_printable_height] (Slic3r::GUI::PartPlateList& plate_list, DynamicPrintConfig& print_config) { - //BBS: translate old 3mf to correct positions - if (translate_old) { - //translate the objects - int plate_count = plate_list.get_plate_count(); - for (int index = 1; index < plate_count; index ++) { - Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); - - Vec3d cur_origin = cur_plate->get_origin(); - Vec3d new_origin = plate_list.compute_origin_using_new_size(index, old_printable_width, old_printable_depth); - - cur_plate->translate_all_instance(new_origin - cur_origin); - } - BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch back to current bed size,{%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height; - plate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true); - } - - if (shrink_to_new_bed) - { - int plate_count = plate_list.get_plate_count(); - ConfigOptionFloats *wipe_x_option = nullptr, *wipe_y_option = nullptr; - Vec3d wipe_offset; - if (print_config.has("wipe_tower_x")) { - wipe_x_option = dynamic_cast(print_config.option("wipe_tower_x")); - wipe_y_option = dynamic_cast(print_config.option("wipe_tower_y")); - } - for (int index = 0; index < plate_count; index ++) { - Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); - - Vec3d cur_origin = cur_plate->get_origin(); - Vec3d new_origin = plate_list.compute_origin_using_new_size(index, current_printable_width, current_printable_depth); - Vec3d cur_center_offset { ((double)old_printable_width)/2, ((double)old_printable_depth)/2, 0}, new_center_offset { ((double)current_printable_width)/2, ((double)current_printable_depth)/2, 0}; - Vec3d cur_center = cur_origin + cur_center_offset; - Vec3d new_center = new_origin + new_center_offset; - Vec3d offset = new_center - cur_center; - - cur_plate->translate_all_instance(offset); - if (index == 0) - wipe_offset = offset; - if (wipe_x_option) { - BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1%: wipe tower src: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index); - ConfigOptionFloat wipe_tower_x(wipe_x_option->get_at(index) + wipe_offset(0)); - ConfigOptionFloat wipe_tower_y(wipe_y_option->get_at(index) + wipe_offset(1)); - - wipe_x_option->set_at(&wipe_tower_x, index, 0); - wipe_y_option->set_at(&wipe_tower_y, index, 0); - BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1% wipe tower changes to: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index); - } - - BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1% translate offset: {%2%, %3%, %4%}")%(index+1) %offset[0] %offset[1] %offset[2]; - } - BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, shrink all the models to current bed size,{%1%, %2%, %3%}")%current_printable_width %current_printable_depth %current_printable_height; - plate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); - } - }; - if (plate_data_src.size() > 0) - { - partplate_list.load_from_3mf_structure(plate_data_src); - - translate_models(partplate_list, m_print_config); - } - - /*for (ModelObject *model_object : m_models[0].objects) - for (ModelInstance *model_instance : model_object->instances) - { - const Vec3d &instance_offset = model_instance->get_offset(); - BOOST_LOG_TRIVIAL(info) << boost::format("instance %1% transform {%2%,%3%,%4%} at %5%:%6%")% model_object->name % instance_offset.x() % instance_offset.y() %instance_offset.z() % __FUNCTION__ % __LINE__<< std::endl; - }*/ - auto timelapse_type_opt = m_print_config.option("timelapse_type"); bool is_smooth_timelapse = false; if (enable_timelapse && timelapse_type_opt && (timelapse_type_opt->getInt() == TimelapseType::tlSmooth)) @@ -3015,6 +2901,366 @@ int CLI::run(int argc, char **argv) } } + //BBS: partplate list + Slic3r::GUI::PartPlateList partplate_list(NULL, m_models.data(), printer_technology); + //use Pointfs insteadof Points + Pointfs current_printable_area = m_print_config.opt("printable_area")->values; + Pointfs current_exclude_area = m_print_config.opt("bed_exclude_area")->values; + //update part plate's size + double print_height = m_print_config.opt_float("printable_height"); + double height_to_lid = m_print_config.opt_float("extruder_clearance_height_to_lid"); + double height_to_rod = m_print_config.opt_float("extruder_clearance_height_to_rod"); + double cleareance_radius = m_print_config.opt_float("extruder_clearance_max_radius"); + //double plate_stride; + std::string bed_texture; + + current_printable_width = current_printable_area[2].x() - current_printable_area[0].x(); + current_printable_depth = current_printable_area[2].y() - current_printable_area[0].y(); + current_printable_height = print_height; + if (old_printable_width == 0) + old_printable_width = current_printable_width; + if (old_printable_depth == 0) + old_printable_depth = current_printable_depth; + if (old_printable_height == 0) + old_printable_height = current_printable_height; + if ((old_printable_width > 0)&&(old_printable_depth > 0)&&(old_printable_height > 0)) + { + //check the printable size logic + //if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth) || (old_printable_height > current_printable_height)) + if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth) || (old_printable_height > current_printable_height)) + { + BOOST_LOG_TRIVIAL(error) << boost::format("old printable size {%1%, %2%, %3%} is larger than new printable size {%4%, %5%, %6%}, the object size should be limited") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + /*record_exit_reson(outfile_dir, CLI_PRINTABLE_SIZE_REDUCED, 0, cli_errors[CLI_PRINTABLE_SIZE_REDUCED], sliced_info); + flush_and_exit(CLI_PRINTABLE_SIZE_REDUCED);*/ + shrink_to_new_bed = 2; + } + else if ((old_printable_width < current_printable_width) || (old_printable_depth < current_printable_depth)) + { + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%} is smaller than new printable size {%4%, %5%, %6%}, need to center the model") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + shrink_to_new_bed = 1; + } + else { + if ((current_exclude_area.size() > 0)&&(current_exclude_area != old_exclude_area)) { + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}, exclude_area different, need to shrink") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + shrink_to_new_bed = 2; + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}, extract the same, no need shrink") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + } + } + } + + if (m_models.size() > 0) + { + BOOST_LOG_TRIVIAL(info) << boost::format("translate_old %1%, shrink_to_new_bed %2%, old bed size {%3%, %4%, %5%}")%translate_old%shrink_to_new_bed %old_printable_width %old_printable_depth %old_printable_height; + if (translate_old) { + BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch to older bed size,{%1%, %2%, %3%}")%(old_printable_width + bed3d_ax3s_default_tip_radius)%(old_printable_depth+bed3d_ax3s_default_tip_radius) %old_printable_height; + partplate_list.reset_size(old_printable_width + bed3d_ax3s_default_tip_radius, old_printable_depth + bed3d_ax3s_default_tip_radius, old_printable_height, false); + } + else { + partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false); + } + partplate_list.set_shapes(current_printable_area, current_exclude_area, bed_texture, height_to_lid, height_to_rod); + //plate_stride = partplate_list.plate_stride_x(); + } + + auto get_print_sequence = [](Slic3r::GUI::PartPlate* plate, DynamicPrintConfig& print_config, bool &is_seq_print) { + PrintSequence curr_plate_seq = plate->get_print_seq(); + if (curr_plate_seq == PrintSequence::ByDefault) { + auto seq_print = print_config.option>("print_sequence"); + if (seq_print && (seq_print->value == PrintSequence::ByObject)) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from global"); + is_seq_print = true; + } + } + else if (curr_plate_seq == PrintSequence::ByObject) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from plate self"); + is_seq_print = true; + } + }; + + auto check_plate_wipe_tower = [get_print_sequence, is_smooth_timelapse](Slic3r::GUI::PartPlate* plate, int plate_index, DynamicPrintConfig& print_config, plate_obj_size_info_t &plate_obj_size_info) { + plate_obj_size_info.obj_bbox= plate->get_objects_bounding_box(); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, object bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}") + %(plate_index+1) %plate_obj_size_info.obj_bbox.min.x() % plate_obj_size_info.obj_bbox.min.y() % plate_obj_size_info.obj_bbox.min.z() %plate_obj_size_info.obj_bbox.max.x() % plate_obj_size_info.obj_bbox.max.y() % plate_obj_size_info.obj_bbox.max.z(); + if (!print_config.has("wipe_tower_x")) { + plate_obj_size_info.has_wipe_tower = false; + BOOST_LOG_TRIVIAL(info) << boost::format("can not found wipe_tower_x in config, set to no wipe tower"); + return; + } + + int valid_count = plate->printable_instance_size(); + if (valid_count <= 0){ + plate_obj_size_info.has_wipe_tower = false; + BOOST_LOG_TRIVIAL(info) << boost::format("no printable object found, set to no wipe tower"); + return; + } + + bool is_sequence = false; + get_print_sequence(plate, print_config, is_sequence); + if (is_sequence && valid_count > 1) { + plate_obj_size_info.has_wipe_tower = false; + BOOST_LOG_TRIVIAL(info) << boost::format("sequence print, valid_count=%1%, set to no wipe tower")%valid_count; + return; + } + + std::vector extruders = plate->get_extruders_under_cli(true, print_config); + unsigned int filaments_cnt = extruders.size(); + if ((filaments_cnt <= 1) && !is_smooth_timelapse){ + plate_obj_size_info.has_wipe_tower = false; + BOOST_LOG_TRIVIAL(info) << boost::format("filaments_cnt=%1%, set to no wipe tower")%filaments_cnt; + return; + } + + ConfigOptionFloats *wipe_x_option = dynamic_cast(print_config.option("wipe_tower_x")); + ConfigOptionFloats *wipe_y_option = dynamic_cast(print_config.option("wipe_tower_y")); + + plate_obj_size_info.wipe_x = wipe_x_option->get_at(plate_index); + plate_obj_size_info.wipe_y = wipe_y_option->get_at(plate_index); + + ConfigOptionFloat* width_option = print_config.option("prime_tower_width", true); + plate_obj_size_info.wipe_width = width_option->value; + + ConfigOptionFloat* brim_width_option = print_config.option("prime_tower_brim_width", true); + float brim_width = brim_width_option->value; + + ConfigOptionFloat* volume_option = print_config.option("prime_volume", true); + float wipe_volume = volume_option->value; + + Vec3d wipe_tower_size = plate->estimate_wipe_tower_size(print_config, plate_obj_size_info.wipe_width, wipe_volume, filaments_cnt); + 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); + 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); + 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%}") + %(plate_index+1) %start.x() % start.y() % start.z() %end.x() % end.y() % end.z(); + }; + + auto translate_models = [translate_old, shrink_to_new_bed, old_printable_width, old_printable_depth, old_printable_height, current_printable_width, current_printable_depth, current_printable_height, current_exclude_area, &plate_obj_size_infos] (Slic3r::GUI::PartPlateList& plate_list, DynamicPrintConfig& print_config) { + //BBS: translate old 3mf to correct positions + if (translate_old) { + //translate the objects + int plate_count = plate_list.get_plate_count(); + for (int index = 1; index < plate_count; index ++) { + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); + + Vec3d cur_origin = cur_plate->get_origin(); + Vec3d new_origin = plate_list.compute_origin_using_new_size(index, old_printable_width, old_printable_depth); + + cur_plate->translate_all_instance(new_origin - cur_origin); + } + BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch back to current bed size,{%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height; + plate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true); + } + + if (shrink_to_new_bed > 0) + { + int plate_count = plate_list.get_plate_count(); + ConfigOptionFloats *wipe_x_option = nullptr, *wipe_y_option = nullptr; + Vec3d wipe_offset; + if (print_config.has("wipe_tower_x")) { + wipe_x_option = dynamic_cast(print_config.option("wipe_tower_x")); + wipe_y_option = dynamic_cast(print_config.option("wipe_tower_y")); + } + double exclude_width = 0.f, exclude_depth = 0.f; + + if (current_exclude_area.size() >= 4) { + exclude_width = current_exclude_area[2].x() - current_exclude_area[0].x(); + exclude_depth = current_exclude_area[2].y() - current_exclude_area[0].y(); + } + for (int index = 0; index < plate_count; index ++) { + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); + Vec3d cur_origin = cur_plate->get_origin(); + Vec3d new_origin = plate_list.compute_origin_using_new_size(index, current_printable_width, current_printable_depth); + Vec3d offset; + + + if (shrink_to_new_bed == 1) { + Vec3d cur_center_offset { ((double)old_printable_width)/2, ((double)old_printable_depth)/2, 0}, new_center_offset { ((double)current_printable_width)/2, ((double)current_printable_depth)/2, 0}; + Vec3d cur_center = cur_origin + cur_center_offset; + Vec3d new_center = new_origin + new_center_offset; + + offset = new_center - cur_center; + + if (index == 0) + wipe_offset = offset; + + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed 1, plate %1%, cur_origin: {%2%, %3%}, new_origin: {%4%, %5%}, cur_center {%6%, %7%} new_center {%8%, %9%}") + %(index+1) %cur_origin(0) %cur_origin(1) %new_origin(0) %new_origin(1) %cur_center(0) %cur_center(1) %new_center(0) %new_center(1); + } + else { + //center the object + Vec3d new_center_offset { ((double)current_printable_width + exclude_width)/2, ((double)current_printable_depth + exclude_depth)/2, 0}; + BoundingBoxf3& bbox = plate_obj_size_infos[index].obj_bbox; + Vec3d size = bbox.size(); + if (size.x() > (current_printable_width - exclude_width)) + new_center_offset(0) = ((double)current_printable_width)/2; + if (size.y() > (current_printable_depth - exclude_depth)) + new_center_offset(1) = ((double)current_printable_depth)/2; + Vec3d new_center = new_origin + new_center_offset; + + offset = new_center - bbox.center(); + + wipe_offset = offset + cur_origin - new_origin; + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed 2, plate %1%, new_origin: {%2%, %3%}, new_center: {%4%, %5%}, obj bbox(including wipe tower) min {%6%, %7%} max {%8%, %9%}") + %(index+1) %new_origin(0) %new_origin(1) %new_center(0) %new_center(1) %bbox.min(0) %bbox.min(1) %bbox.max(0) %bbox.max(1); + } + offset(2) = 0.f; + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed %1%, plate %2% translate offset: {%3%, %4%} wipe_offset {%5%, %6%}") %shrink_to_new_bed %(index+1) %offset[0] %offset[1] %wipe_offset[0] %wipe_offset[1]; + cur_plate->translate_all_instance(offset); + + if (wipe_x_option) { + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed %4%, plate %1%: wipe tower src: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index)%shrink_to_new_bed; + ConfigOptionFloat wipe_tower_x(wipe_x_option->get_at(index) + wipe_offset(0)); + ConfigOptionFloat wipe_tower_y(wipe_y_option->get_at(index) + wipe_offset(1)); + + wipe_x_option->set_at(&wipe_tower_x, index, 0); + wipe_y_option->set_at(&wipe_tower_y, index, 0); + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed %4%, plate %1% wipe tower changes to: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index) %shrink_to_new_bed; + } + + + } + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, shrink all the models to current bed size,{%1%, %2%, %3%}")%current_printable_width %current_printable_depth %current_printable_height; + plate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); + } + }; + if (plate_data_src.size() > 0) + { + partplate_list.load_from_3mf_structure(plate_data_src); + + int plate_count = partplate_list.get_plate_count(); + plate_obj_size_infos.resize(plate_count, plate_obj_size_info_t()); + for (int index = 0; index < plate_count; index ++) { + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index); + + check_plate_wipe_tower(cur_plate, index, m_print_config, plate_obj_size_infos[index]); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, has_wipe_tower %2%, wipe_x %3%, wipe_y %4%, width %5%, depth %6%") + %(index+1) %plate_obj_size_infos[index].has_wipe_tower %plate_obj_size_infos[index].wipe_x %plate_obj_size_infos[index].wipe_y %plate_obj_size_infos[index].wipe_width %plate_obj_size_infos[index].wipe_depth; + } + + translate_models(partplate_list, m_print_config); + } + + /*for (ModelObject *model_object : m_models[0].objects) + for (ModelInstance *model_instance : model_object->instances) + { + const Vec3d &instance_offset = model_instance->get_offset(); + BOOST_LOG_TRIVIAL(info) << boost::format("instance %1% transform {%2%,%3%,%4%} at %5%:%6%")% model_object->name % instance_offset.x() % instance_offset.y() %instance_offset.z() % __FUNCTION__ % __LINE__<< std::endl; + }*/ + + //doing downward_check + std::vector downward_check_printers; + std::vector downward_check_status; + for (auto const &file : downward_check) { + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from, downward_printer; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + if ((config_type != "machine") || (config_from != "system")) { + BOOST_LOG_TRIVIAL(info) << boost::format("found invalid config type %1% or from %2% in file %3% when downward_check")%config_type %config_from %file; + record_exit_reson(outfile_dir, ret, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(ret); + + } + BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: loaded machine config %1%, from %2%")%config_name %file ; + + printer_plate_info_t printer_plate; + Pointfs temp_printable_area, temp_exclude_area; + + printer_plate.printer_name = config_name; + + temp_printable_area = config.option("printable_area", true)->values; + temp_exclude_area = config.option("bed_exclude_area", true)->values; + if (temp_printable_area.size() >= 4) { + printer_plate.printable_width = (int)(temp_printable_area[2].x() - temp_printable_area[0].x()); + printer_plate.printable_depth = (int)(temp_printable_area[2].y() - temp_printable_area[0].y()); + printer_plate.printable_height = (int)(config.opt_float("printable_height")); + } + if (temp_exclude_area.size() >= 4) { + printer_plate.exclude_width = (int)(temp_exclude_area[2].x() - temp_exclude_area[0].x()); + printer_plate.exclude_depth = (int)(temp_exclude_area[2].y() - temp_exclude_area[0].y()); + printer_plate.exclude_x = (int)temp_exclude_area[0].x(); + printer_plate.exclude_y = (int)temp_exclude_area[0].y(); + } + BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: printable size{%1%,%2%, %3%}, exclude area{%4%, %5%: %6% x %7%}") + %printer_plate.printable_width %printer_plate.printable_depth %printer_plate.printable_height + %printer_plate.exclude_x %printer_plate.exclude_y %printer_plate.exclude_width %printer_plate.exclude_depth; + downward_check_printers.push_back(std::move(printer_plate)); + } + + int downward_check_size = downward_check_printers.size(); + if (downward_check_size > 0) + { + downward_check_status.resize(downward_check_size, false); + int plate_count = partplate_list.get_plate_count(); + int failed_count = 0; + for (int index = 0; index < plate_count; index ++) + { + if (failed_count == downward_check_size) { + BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: all failed, size %1%")%downward_check_size; + break; + } + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index); + Vec3d size = plate_obj_size_infos[index].obj_bbox.size(); + + for (int index2 = 0; index2 < downward_check_size; index2 ++) + { + if (failed_count == downward_check_size) { + break; + } + if (downward_check_status[index2]) + continue; + printer_plate_info_t& plate_info = downward_check_printers[index2]; + if ((size.z() > plate_info.printable_height) || (size.y() > plate_info.printable_depth) || (size.x() > plate_info.printable_width)) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, downward_check index %2%, name %3%, bbox {%4%, %5%, %6%} exceeds printer size {%7%, %8%, %9%}") + %(index+1) %(index2+1) %plate_info.printer_name + %size.x() % size.y() % size.z() %plate_info.printable_width %plate_info.printable_depth %plate_info.printable_height; + downward_check_status[index2] = true; + failed_count ++; + continue; + } + if (plate_info.exclude_width > 0) { + int real_width = plate_info.printable_width - plate_info.exclude_width; + int real_depth = plate_info.printable_depth - plate_info.exclude_depth; + if ((size.x() > real_width) && (size.y() > real_depth)) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, downward_check index %2%, name %3%, bbox {%4%, %5%} exceeds real size without exclude_area {%6%, %7%}") + %(index+1) %(index2+1) %plate_info.printer_name + %size.x() % size.y() %real_width %real_depth; + downward_check_status[index2] = true; + failed_count ++; + continue; + } + } + } + } + if (failed_count < downward_check_size) + { + //has success ones + BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: downward_check_size %1%, failed_count %2%")%downward_check_size %failed_count; + for (int index2 = 0; index2 < downward_check_size; index2 ++) + { + if (downward_check_status[index2]) + continue; + printer_plate_info_t& plate_info = downward_check_printers[index2]; + BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: found compatible printer %1%")%plate_info.printer_name; + downward_compatible_machines.push_back(plate_info.printer_name); + } + sliced_info.downward_machines = downward_compatible_machines; + } + } + // Loop through transform options. bool user_center_specified = false; Points beds = get_bed_shape(m_print_config); @@ -3410,21 +3656,6 @@ int CLI::run(int argc, char **argv) } } - auto get_print_sequence = [](Slic3r::GUI::PartPlate* plate, DynamicPrintConfig& print_config, bool &is_seq_print) { - PrintSequence curr_plate_seq = plate->get_print_seq(); - if (curr_plate_seq == PrintSequence::ByDefault) { - auto seq_print = print_config.option>("print_sequence"); - if (seq_print && (seq_print->value == PrintSequence::ByObject)) { - BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from global"); - is_seq_print = true; - } - } - else if (curr_plate_seq == PrintSequence::ByObject) { - BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from plate self"); - is_seq_print = true; - } - }; - if (!assemble_plate_info_list.empty()) { //need to arrange for assemble cases @@ -4241,7 +4472,7 @@ 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 no_check = false; - std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir; + std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir, export_stls_dir; 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; @@ -4275,9 +4506,9 @@ int CLI::run(int argc, char **argv) record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); flush_and_exit(CLI_INVALID_PARAMS); } - else if (shrink_to_new_bed) + else if (shrink_to_new_bed > 0) { - BOOST_LOG_TRIVIAL(warning) << "use load_slicedata when shrink_to_new_bed(switch printer from small to bigger." << std::endl; + BOOST_LOG_TRIVIAL(warning) << "use load_slicedata when shrink_to_new_bed." << std::endl; //record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); //flush_and_exit(CLI_INVALID_PARAMS); } @@ -4309,6 +4540,14 @@ int CLI::run(int argc, char **argv) record_exit_reson(outfile_dir, CLI_EXPORT_STL_ERROR, 0, cli_errors[CLI_EXPORT_STL_ERROR], sliced_info); flush_and_exit(CLI_EXPORT_STL_ERROR); } + } else if (opt_key == "export_stls") { + export_stls_dir = m_config.opt_string(opt_key); + for (auto &model : m_models) + model.add_default_instances(); + if (! this->export_models(IO::STL, export_stls_dir)) { + record_exit_reson(outfile_dir, CLI_EXPORT_STL_ERROR, 0, cli_errors[CLI_EXPORT_STL_ERROR], sliced_info); + flush_and_exit(CLI_EXPORT_STL_ERROR); + } } else if (opt_key == "export_obj") { for (auto &model : m_models) model.add_default_instances(); @@ -5666,7 +5905,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn }*/ } -bool CLI::export_models(IO::ExportFormat format) +bool CLI::export_models(IO::ExportFormat format, std::string path_dir) { for (Model &model : m_models) { const std::string path = this->output_filepath(model, format); @@ -5687,7 +5926,7 @@ bool CLI::export_models(IO::ExportFormat format) unsigned int index = 1; for (ModelObject* model_object : model.objects) { - const std::string path = this->output_filepath(*model_object, index++, format); + const std::string path = this->output_filepath(*model_object, index++, format, path_dir); success = Slic3r::store_stl(path.c_str(), model_object, true); if (success) BOOST_LOG_TRIVIAL(info) << "Model successfully exported to " << path << std::endl; @@ -5770,7 +6009,7 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co return proposed_path.string(); } -std::string CLI::output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const +std::string CLI::output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format, std::string path_dir) const { std::string ext, subdir, file_name, output_path; switch (format) { @@ -5799,10 +6038,15 @@ std::string CLI::output_filepath(const ModelObject &object, unsigned int index, if (pos != ext_pos) file_name += ext; - BOOST_LOG_TRIVIAL(trace) << __FUNCTION__ << ": file_name="<& project_presets, std::vector &thumbnails, @@ -99,7 +121,7 @@ private: bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } std::string output_filepath(const Model &model, IO::ExportFormat format) const; - std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const; + std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format, std::string path_dir) const; }; } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7b74d804d..02e40879f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5406,9 +5406,14 @@ CLIActionsConfigDef::CLIActionsConfigDef() def = this->add("export_stl", coBool); def->label = "Export STL"; - def->tooltip = "Export the objects as multiple STL."; + def->tooltip = "Export the objects as single STL."; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("export_stls", coString); + def->label = "Export multiple stls"; + def->tooltip = "Export the objects as multiple stls to directory"; + def->set_default_value(new ConfigOptionString("stl_path")); + /*def = this->add("export_gcode", coBool); def->label = L("Export G-code"); def->tooltip = L("Slice the model and export toolpaths as G-code."); @@ -5688,6 +5693,12 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->cli_params = "\"filament1.json;filament2.json;...\""; def->set_default_value(new ConfigOptionStrings()); + def = this->add("downward_check", coStrings); + def->label = "downward machines check"; + def->tooltip = "check whether current machine downward compatible with the machines in the list"; + def->cli_params = "\"machine1.json;machine2.json;...\""; + def->set_default_value(new ConfigOptionStrings()); + def = this->add("load_assemble_list", coString); def->label = "Load assemble list"; def->tooltip = "Load assemble object list from config file"; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index b62ab34c1..5be069538 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2216,6 +2216,28 @@ int PartPlate::remove_instance(int obj_id, int instance_id) return result; } +BoundingBoxf3 PartPlate::get_objects_bounding_box() +{ + BoundingBoxf3 bbox; + for (std::set>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it) + { + int obj_id = it->first; + int instance_id = it->second; + + if ((obj_id >= 0) && (obj_id < m_model->objects.size())) + { + ModelObject* object = m_model->objects[obj_id]; + if ((instance_id >= 0) && (instance_id < object->instances.size())) + { + BoundingBoxf3 instance_bbox = object->instance_bounding_box(instance_id); + bbox.merge(instance_bbox); + } + } + } + return bbox; +} + + //translate instance on the plate void PartPlate::translate_all_instance(Vec3d position) { diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index c1e703248..4e9799fee 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -304,6 +304,7 @@ public: ModelObjectPtrs get_objects() { return m_model->objects; } ModelObjectPtrs get_objects_on_this_plate(); ModelInstance* get_instance(int obj_id, int instance_id); + BoundingBoxf3 get_objects_bounding_box(); Vec3d get_origin() { return m_origin; } Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const;