ENH: CLI: add the repetitions logic

support to duplicate object in a plate

Change-Id: I6bc964a2b9660adf3be7919f230524c979da9d50
This commit is contained in:
lane.wei 2023-07-22 20:04:17 +08:00 committed by Lane.Wei
parent b8fa5decc1
commit 99bbce0f0f
3 changed files with 507 additions and 129 deletions

View File

@ -349,7 +349,7 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config)
return(ret);}
#endif
void record_fail_reson(std::string outputdir, int code, int plate_id, std::string error_message)
void record_exit_reson(std::string outputdir, int code, int plate_id, std::string error_message, int extra_param1 = 0)
{
#if defined(__linux__) || defined(__LINUX__)
std::string result_file;
@ -365,6 +365,8 @@ void record_fail_reson(std::string outputdir, int code, int plate_id, std::strin
j["plate_index"] = plate_id;
j["return_code"] = code;
j["error_string"] = error_message;
if (extra_param1 != 0)
j["extra_param1"] = extra_param1;
boost::nowide::ofstream c;
c.open(result_file, std::ios::out | std::ios::trunc);
@ -425,16 +427,16 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << "index="<< index <<", arg is "<< argv[index] <<std::endl;
int debug_argc = 7;
char *debug_argv[] = {
"E:\work\projects\bambu_debug\bamboo_slicer\build_debug\src\Debug\bambu-studio.exe",
"F:\work\projects\bambu_debug\bamboo_slicer\build_debug\src\Debug\bambu-studio.exe",
//"--uptodate",
//"--load-settings",
//"machine.json;process.json",
"--load-slicedata",
"cached_data",
"--repetitions",
"3",
"--export-3mf=output.3mf",
"--slice",
"0",
"boats.3mf"
"1",
"test_repetitions.3mf"
};
if (! this->setup(debug_argc, debug_argv))*/
if (!this->setup(argc, argv))
@ -545,8 +547,8 @@ int CLI::run(int argc, char **argv)
//BBS: add plate data related logic
PlateDataPtrs plate_data_src;
int arrange_option;
int plate_to_slice = 0, filament_count = 0, 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;
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;
Semver file_version;
std::map<size_t, bool> orients_requirement;
std::vector<Preset*> project_presets;
@ -594,7 +596,7 @@ int CLI::run(int argc, char **argv)
for (const std::string& file : m_input_files) {
if (!boost::filesystem::exists(file)) {
boost::nowide::cerr << "No such file: " << file << std::endl;
record_fail_reson(outfile_dir, CLI_FILE_NOTFOUND, 0, cli_errors[CLI_FILE_NOTFOUND]);
record_exit_reson(outfile_dir, CLI_FILE_NOTFOUND, 0, cli_errors[CLI_FILE_NOTFOUND]);
flush_and_exit(CLI_FILE_NOTFOUND);
}
Model model;
@ -624,7 +626,7 @@ int CLI::run(int argc, char **argv)
if (!first_file)
{
BOOST_LOG_TRIVIAL(info) << "The BBL 3mf file should be placed at the first position, filename=" << file << "\n";
record_fail_reson(outfile_dir, CLI_FILELIST_INVALID_ORDER, 0, cli_errors[CLI_FILELIST_INVALID_ORDER]);
record_exit_reson(outfile_dir, CLI_FILELIST_INVALID_ORDER, 0, cli_errors[CLI_FILELIST_INVALID_ORDER]);
flush_and_exit(CLI_FILELIST_INVALID_ORDER);
}
BOOST_LOG_TRIVIAL(info) << "the first file is a 3mf, got plate count:" << plate_data_src.size() << "\n";
@ -651,7 +653,7 @@ int CLI::run(int argc, char **argv)
std::vector<std::string> postprocess_values = postprocess_scripts->values;
if (postprocess_values.size() > 0) {
BOOST_LOG_TRIVIAL(error) << boost::format("normative_check: postprocess not supported, array size %1%")%postprocess_values.size();
record_fail_reson(outfile_dir, CLI_POSTPROCESS_NOT_SUPPORTED, 0, cli_errors[CLI_POSTPROCESS_NOT_SUPPORTED]);
record_exit_reson(outfile_dir, CLI_POSTPROCESS_NOT_SUPPORTED, 0, cli_errors[CLI_POSTPROCESS_NOT_SUPPORTED]);
flush_and_exit(CLI_POSTPROCESS_NOT_SUPPORTED);
}
}
@ -726,7 +728,7 @@ int CLI::run(int argc, char **argv)
}
if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) {
boost::nowide::cerr << "invalid printer_technology " <<printer_technology<<", from source file "<< file <<std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
flush_and_exit(CLI_INVALID_PRINTER_TECH);
}
if (!config_substitutions.substitutions.empty()) {
@ -741,7 +743,7 @@ int CLI::run(int argc, char **argv)
}
catch (std::exception& e) {
boost::nowide::cerr << file << ": " << e.what() << std::endl;
record_fail_reson(outfile_dir, CLI_DATA_FILE_ERROR, 0, cli_errors[CLI_DATA_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_DATA_FILE_ERROR, 0, cli_errors[CLI_DATA_FILE_ERROR]);
flush_and_exit(CLI_DATA_FILE_ERROR);
}
if (model.objects.empty()) {
@ -828,14 +830,14 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(file, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
if (config_type == "machine") {
if (!new_printer_name.empty()) {
boost::nowide::cerr << "duplicate machine config file: " << file << std::endl;
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
new_printer_name = config_name;
@ -846,7 +848,7 @@ int CLI::run(int argc, char **argv)
else if (config_type == "process") {
if (!new_process_name.empty()) {
boost::nowide::cerr << "duplicate process config file: " << file << std::endl;
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
new_process_name = config_name;
@ -863,7 +865,7 @@ int CLI::run(int argc, char **argv)
if ((printer_technology != other_printer_technology)&&(other_printer_technology != ptUnknown)){
boost::nowide::cerr << "invalid printer_technology " <<printer_technology<<", from config "<< file <<std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
flush_and_exit(CLI_INVALID_PRINTER_TECH);
}
}
@ -883,13 +885,13 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(file, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
if (config_type != "filament") {
boost::nowide::cerr <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file;
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
@ -899,7 +901,7 @@ int CLI::run(int argc, char **argv)
}
if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) {
boost::nowide::cerr << "invalid printer_technology " <<printer_technology<<", from filament file "<< file <<std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
flush_and_exit(CLI_INVALID_PRINTER_TECH);
}
load_filaments_id.push_back(filament_id);
@ -930,7 +932,7 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(system_printer_path, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
upward_compatible_printers = config.option<ConfigOptionStrings>("upward_compatible_machine", true)->values;
@ -953,7 +955,7 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(system_process_path, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
current_print_compatible_printers = config.option<ConfigOptionStrings>("compatible_printers", true)->values;
@ -976,7 +978,7 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(system_filament_path, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
@ -1006,7 +1008,7 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(system_printer_path, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
upward_compatible_printers = config.option<ConfigOptionStrings>("upward_compatible_machine", true)->values;
@ -1028,7 +1030,7 @@ int CLI::run(int argc, char **argv)
std::string config_type, config_name, filament_id;
int ret = load_system_config_file(system_process_path, config, config_type, config_name, filament_id);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
current_print_compatible_printers = config.option<ConfigOptionStrings>("compatible_printers", true)->values;
@ -1103,20 +1105,20 @@ int CLI::run(int argc, char **argv)
}
if (!process_compatible) {
boost::nowide::cout <<__FUNCTION__ << boost::format(": current 3mf file not support the new printer %1%")%new_printer_name;
record_fail_reson(outfile_dir, CLI_3MF_NEW_MACHINE_NOT_SUPPORTED, 0, cli_errors[CLI_3MF_NEW_MACHINE_NOT_SUPPORTED]);
record_exit_reson(outfile_dir, CLI_3MF_NEW_MACHINE_NOT_SUPPORTED, 0, cli_errors[CLI_3MF_NEW_MACHINE_NOT_SUPPORTED]);
flush_and_exit(CLI_3MF_NEW_MACHINE_NOT_SUPPORTED);
}
}
else {
boost::nowide::cout <<__FUNCTION__ << boost::format(": current 3mf file not support upward_compatible_printers, can not change machine preset.");
record_fail_reson(outfile_dir, CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE, 0, cli_errors[CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE]);
record_exit_reson(outfile_dir, CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE, 0, cli_errors[CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE]);
flush_and_exit(CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE);
}
}
if (!process_compatible) {
boost::nowide::cout <<__FUNCTION__ << boost::format(": process not compatible with printer.");
record_fail_reson(outfile_dir, CLI_PROCESS_NOT_COMPATIBLE, 0, cli_errors[CLI_PROCESS_NOT_COMPATIBLE]);
record_exit_reson(outfile_dir, CLI_PROCESS_NOT_COMPATIBLE, 0, cli_errors[CLI_PROCESS_NOT_COMPATIBLE]);
flush_and_exit(CLI_PROCESS_NOT_COMPATIBLE);
}
@ -1220,7 +1222,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << boost::format("update printer config to newest, different size %1%")%different_keys_set.size();
int ret = update_full_config(m_print_config, load_machine_config, different_keys_set);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
}
@ -1260,7 +1262,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << boost::format("update process config to newest, different size %1%")%different_keys_set.size();
int ret = update_full_config(m_print_config, load_process_config, different_keys_set);
if (ret) {
record_fail_reson(outfile_dir, ret, 0, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret]);
flush_and_exit(ret);
}
}
@ -1340,7 +1342,7 @@ int CLI::run(int argc, char **argv)
if (source_opt == nullptr) {
// The key was not found in the source config, therefore it will not be initialized!
BOOST_LOG_TRIVIAL(error) << boost::format("can not find %1% from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index];
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
if (source_opt->is_scalar()) {
@ -1373,7 +1375,7 @@ int CLI::run(int argc, char **argv)
// opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def().
// This is only possible if other is of DynamicConfig type.
BOOST_LOG_TRIVIAL(error) << boost::format("can not create option %1% to config, from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index];
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt);
@ -1429,7 +1431,7 @@ int CLI::run(int argc, char **argv)
if (filament_is_support->size() != project_filament_count)
{
BOOST_LOG_TRIVIAL(error) << boost::format("filament_is_support's count %1% not equal to filament_colour's size %2%")%filament_is_support->size() %project_filament_count;
record_fail_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR]);
flush_and_exit(CLI_CONFIG_FILE_ERROR);
}
@ -1526,7 +1528,7 @@ int CLI::run(int argc, char **argv)
m_print_config.apply(fff_print_config, true);
} else {
boost::nowide::cerr << "invalid printer_technology " << std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH]);
flush_and_exit(CLI_INVALID_PRINTER_TECH);
/*assert(printer_technology == ptSLA);
sla_print_config.filename_format.value = "[input_filename_base].sl1";
@ -1546,7 +1548,7 @@ int CLI::run(int argc, char **argv)
boost::nowide::cerr << "Param values in 3mf/config error: "<< std::endl;
for (std::map<std::string, std::string>::iterator it=validity.begin(); it!=validity.end(); ++it)
boost::nowide::cerr << it->first <<": "<< it->second << std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_VALUES_IN_3MF, 0, cli_errors[CLI_INVALID_VALUES_IN_3MF]);
record_exit_reson(outfile_dir, CLI_INVALID_VALUES_IN_3MF, 0, cli_errors[CLI_INVALID_VALUES_IN_3MF]);
flush_and_exit(CLI_INVALID_VALUES_IN_3MF);
}
@ -1559,6 +1561,7 @@ int CLI::run(int argc, char **argv)
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;
@ -1578,7 +1581,7 @@ int CLI::run(int argc, char **argv)
{
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_fail_reson(outfile_dir, CLI_PRINTABLE_SIZE_REDUCED, 0, cli_errors[CLI_PRINTABLE_SIZE_REDUCED]);
record_exit_reson(outfile_dir, CLI_PRINTABLE_SIZE_REDUCED, 0, cli_errors[CLI_PRINTABLE_SIZE_REDUCED]);
flush_and_exit(CLI_PRINTABLE_SIZE_REDUCED);
}
else if ((old_printable_width < current_printable_width) || (old_printable_depth < current_printable_depth))
@ -1693,9 +1696,21 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << "invalid repetitions value " << repetitions_count << ", just skip\n";
}
else {
//todo
//copy model objects and instances
if (plate_to_slice == 0) {
BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set repetitions when slice all." << std::endl;
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
else if (plate_to_slice > partplate_list.get_plate_count()) {
BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params:invalid plate %1% to slice, total %2%")%plate_to_slice %partplate_list.get_plate_count();
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
BOOST_LOG_TRIVIAL(info) << "repetitions value " << repetitions_count << ", will copy model object first\n";
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
//copy model objects and instances on plate
cur_plate->duplicate_all_instance(repetitions_count-1);
need_arrange = true;
duplicate_count = repetitions_count - 1;
}
@ -1745,7 +1760,7 @@ int CLI::run(int argc, char **argv)
}
} catch (std::exception &ex) {
boost::nowide::cerr << "error: " << ex.what() << std::endl;
record_fail_reson(outfile_dir, CLI_COPY_OBJECTS_ERROR, 0, cli_errors[CLI_COPY_OBJECTS_ERROR]);
record_exit_reson(outfile_dir, CLI_COPY_OBJECTS_ERROR, 0, cli_errors[CLI_COPY_OBJECTS_ERROR]);
flush_and_exit(CLI_COPY_OBJECTS_ERROR);
}
}
@ -1815,7 +1830,7 @@ int CLI::run(int argc, char **argv)
const Vec3d &opt = m_config.opt<ConfigOptionPoint3>(opt_key)->value;
if (opt.x() <= 0 || opt.y() <= 0 || opt.z() <= 0) {
boost::nowide::cerr << "--scale-to-fit requires a positive volume" << std::endl;
record_fail_reson(outfile_dir, CLI_SCALE_TO_FIT_ERROR, 0, cli_errors[CLI_SCALE_TO_FIT_ERROR]);
record_exit_reson(outfile_dir, CLI_SCALE_TO_FIT_ERROR, 0, cli_errors[CLI_SCALE_TO_FIT_ERROR]);
flush_and_exit(CLI_SCALE_TO_FIT_ERROR);
}
for (auto &model : m_models)
@ -1906,7 +1921,7 @@ int CLI::run(int argc, char **argv)
// model.repair();
} else {
boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
record_fail_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION]);
record_exit_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION]);
flush_and_exit(CLI_UNSUPPORTED_OPERATION);
}
}
@ -1934,51 +1949,175 @@ int CLI::run(int argc, char **argv)
orients_requirement.clear();
oriented_or_arranged |= need_arrange;
BOOST_LOG_TRIVIAL(info) << boost::format("before arrange, need_arrange=%1%, duplicate_count %2%")%need_arrange%duplicate_count;
if (need_arrange)
{
ArrangePolygons selected, unselected, unprintable, locked_aps;
BOOST_LOG_TRIVIAL(info) << "Will arrange now, need_arrange="<<need_arrange<<"\n";
for (Model &model : m_models)
//for (Model &model : m_models)
if (m_models.size() > 0)
{
//Step-1: prepare arrange polygons
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx)
{
ModelObject* mo = model.objects[oidx];
for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx)
{
ModelInstance* minst = mo->instances[inst_idx];
ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config);
Model &model = m_models[0];
//preprocess by partplate list
//remove the locked plate's instances, neither in selected, nor in un-selected
bool locked = partplate_list.preprocess_arrange_polygon(oidx, inst_idx, ap, true);
if (!locked)
arrange_cfg.is_seq_print = false;
//Step-1: prepare arrange polygons
if (duplicate_count == 0)
{
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx)
{
ModelObject* mo = model.objects[oidx];
for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx)
{
ap.itemid = selected.size();
if (minst->printable)
selected.emplace_back(ap);
ModelInstance* minst = mo->instances[inst_idx];
ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config);
//preprocess by partplate list
//remove the locked plate's instances, neither in selected, nor in un-selected
bool locked = partplate_list.preprocess_arrange_polygon(oidx, inst_idx, ap, true);
if (!locked)
{
ap.itemid = selected.size();
if (minst->printable)
selected.emplace_back(ap);
else
unprintable.emplace_back(ap);
}
else
unprintable.emplace_back(ap);
}
else
{
//skip this object due to be locked in plate
ap.itemid = locked_aps.size();
locked_aps.emplace_back(ap);
boost::nowide::cout <<__FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx;
{
//skip this object due to be locked in plate
ap.itemid = locked_aps.size();
locked_aps.emplace_back(ap);
boost::nowide::cout <<__FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx;
}
}
}
if (m_print_config.has("print_sequence")) {
PrintSequence seq = m_print_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence")->value;
arrange_cfg.is_seq_print = (seq == PrintSequence::ByObject);
}
//add the virtual object into unselect list if has
partplate_list.preprocess_exclude_areas(unselected);
}
else {
//only arrange current plate
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
PrintSequence curr_plate_seq = cur_plate->get_print_seq();
if (curr_plate_seq == PrintSequence::ByDefault) {
auto seq_print = m_print_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence");
if (seq_print && (seq_print->value == PrintSequence::ByObject)) {
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% print by object, set from global")%plate_to_slice;
arrange_cfg.is_seq_print = true;
}
}
else if (curr_plate_seq == PrintSequence::ByObject) {
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% print by object, set from plate self")%plate_to_slice;
arrange_cfg.is_seq_print = true;
}
partplate_list.lock_plate(plate_to_slice - 1, false);
partplate_list.select_plate(plate_to_slice-1);
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% set to selected")%plate_to_slice;
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx)
{
ModelObject* mo = model.objects[oidx];
for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx)
{
ModelInstance* minst = mo->instances[inst_idx];
bool in_plate = cur_plate->contain_instance(oidx, inst_idx) || cur_plate->intersect_instance(oidx, inst_idx);
ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config);
ArrangePolygons& cont = mo->instances[inst_idx]->printable ?
(in_plate ? selected : unselected) :
unprintable;
bool locked = partplate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate);
BOOST_LOG_TRIVIAL(info) << boost::format("name %4% in_plate %1% printable %2%, locked %3%")%in_plate %mo->instances[inst_idx]->printable %locked % ap.name ;
if (!locked)
{
ap.itemid = cont.size();
cont.emplace_back(std::move(ap));
}
else
{
//skip this object due to be not in current plate, treated as locked
ap.itemid = locked_aps.size();
locked_aps.emplace_back(std::move(ap));
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, name %2%") % oidx % mo->name;
}
}
}
if (selected.size() == (duplicate_count + 1))
{
duplicate_single_object = true;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found single object mode");
}
if (m_print_config.has("wipe_tower_x")) {
float x = dynamic_cast<const ConfigOptionFloats *>(m_print_config.option("wipe_tower_x"))->get_at(plate_to_slice-1);
float y = dynamic_cast<const ConfigOptionFloats *>(m_print_config.option("wipe_tower_y"))->get_at(plate_to_slice-1);
float w = dynamic_cast<const ConfigOptionFloat *>(m_print_config.option("prime_tower_width"))->value;
float a = dynamic_cast<const ConfigOptionFloat *>(m_print_config.option("wipe_tower_rotation_angle"))->value;
float v = dynamic_cast<const ConfigOptionFloat *>(m_print_config.option("prime_volume"))->value;
unsigned int filaments_cnt = plate_data_src[plate_to_slice-1]->slice_filaments_info.size();
if (filaments_cnt == 0)
{
// slice filaments info invalid
std::vector<int> extruders = cur_plate->get_extruders_under_cli(true, m_print_config);
filaments_cnt = extruders.size();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": slice filaments info invalid, get from partplate: filament_count %1%")%filaments_cnt;
}
float layer_height = 0.2;
ConfigOption* layer_height_opt = m_print_config.option("layer_height");
if (layer_height_opt)
layer_height = layer_height_opt->getFloat();
float depth = v * (filaments_cnt - 1) / (layer_height * w);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("wipe_tower: x=%1%, y=%2%, width=%3%, depth=%4%, angle=%5%, prime_volume=%6%, filaments_cnt=%7%, layer_height=%8%")
%x %y %w %depth %a %v %filaments_cnt %layer_height;
Vec3d plate_origin = cur_plate->get_origin();
ArrangePolygon wipe_tower_ap;
Polygon ap({
{scaled(x), scaled(y)},
{scaled(x + w), scaled(y)},
{scaled(x + w), scaled(y + depth)},
{scaled(x), scaled(y + depth)}
});
wipe_tower_ap.bed_idx = 0;
wipe_tower_ap.setter = NULL; // do not move wipe tower
wipe_tower_ap.poly.contour = std::move(ap);
wipe_tower_ap.translation = {scaled(0.f), scaled(0.f)};
wipe_tower_ap.rotation = a;
wipe_tower_ap.name = "WipeTower";
wipe_tower_ap.is_virt_object = true;
wipe_tower_ap.is_wipe_tower = true;
++wipe_tower_ap.priority;
unselected.emplace_back(std::move(wipe_tower_ap));
}
// add the virtual object into unselect list if has
partplate_list.preprocess_exclude_areas(unselected, plate_to_slice);
}
//add the virtual object into unselect list if has
partplate_list.preprocess_exclude_areas(unselected);
//Step-2:prepare the arrange params
arrange_cfg.allow_rotations = true;
arrange_cfg.min_obj_distance = scaled(6.0);
//BBS: add specific params
arrange_cfg.is_seq_print = false;
arrange_cfg.allow_multi_materials_on_same_plate = true;
arrange_cfg.avoid_extrusion_cali_region = false;
arrange_cfg.min_obj_distance = scaled(22.0);
arrange_cfg.clearance_height_to_rod = height_to_rod;
arrange_cfg.clearance_height_to_lid = height_to_lid;
arrange_cfg.cleareance_radius = cleareance_radius;
arrange_cfg.printable_height = print_height;
arrange_cfg.bed_shrink_x = 0;
arrange_cfg.bed_shrink_y = 0;
double skirt_distance = m_print_config.opt_float("skirt_distance");
@ -1990,6 +2129,14 @@ int CLI::run(int argc, char **argv)
// So we can't do max but do adding instead.
arrange_cfg.bed_shrink_x += arrange_cfg.brim_skirt_distance;
arrange_cfg.bed_shrink_y += arrange_cfg.brim_skirt_distance;
if (arrange_cfg.is_seq_print)
{
arrange_cfg.min_obj_distance = std::max(arrange_cfg.min_obj_distance, scaled(arrange_cfg.cleareance_radius + 0.001));
float shift_dist = arrange_cfg.cleareance_radius / 2 - 5;
arrange_cfg.bed_shrink_x -= shift_dist;
arrange_cfg.bed_shrink_y -= shift_dist;
}
// shrink bed
beds[0] += Point(scaled(arrange_cfg.bed_shrink_x), scaled(arrange_cfg.bed_shrink_y));
beds[1] += Point(-scaled(arrange_cfg.bed_shrink_x), scaled(arrange_cfg.bed_shrink_y));
@ -2015,43 +2162,133 @@ int CLI::run(int argc, char **argv)
//Step-4:postprocess by partplate list&&apply the result
int bed_idx_max = 0;
//clear all the relations before apply the arrangement results
partplate_list.clear();
if (duplicate_count == 0)
{
//clear all the relations before apply the arrangement results
partplate_list.clear();
// Apply the arrange result to all selected objects
for (ArrangePolygon &ap : selected) {
//BBS: partplate postprocess
partplate_list.postprocess_bed_index_for_selected(ap);
// Apply the arrange result to all selected objects
for (ArrangePolygon &ap : selected) {
//BBS: partplate postprocess
partplate_list.postprocess_bed_index_for_selected(ap);
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
boost::nowide::cout<< "after arrange: name=" << ap.name << boost::format(",bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) << "\n";
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
boost::nowide::cout<< "after arrange: name=" << ap.name << boost::format(",bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) << "\n";
}
for (ArrangePolygon &ap : locked_aps) {
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
partplate_list.postprocess_arrange_polygon(ap, false);
ap.apply();
}
// Apply the arrange result to all selected objects
for (ArrangePolygon &ap : selected) {
//BBS: partplate postprocess
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
}
// Move the unprintable items to the last virtual bed.
for (ArrangePolygon &ap : unprintable) {
ap.bed_idx += bed_idx_max + 1;
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
}
//BBS: reload all objects due to arrange
partplate_list.rebuild_plates_after_arrangement();
}
for (ArrangePolygon &ap : locked_aps) {
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
else {
//only for partplate case
partplate_list.clear(false, false, true, plate_to_slice-1);
partplate_list.postprocess_arrange_polygon(ap, false);
//BBS: adjust the bed_index, create new plates, get the max bed_index
ap.apply();
for (ArrangePolygon& ap : selected) {
if (ap.bed_idx != (plate_to_slice-1))
{
//
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.name % ap.bed_idx % (plate_to_slice-1);
if (!duplicate_single_object)
{
BOOST_LOG_TRIVIAL(error) << "arrange failed when duplicate multiple objects." << std::endl;
record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED]);
flush_and_exit(CLI_OBJECT_ARRANGE_FAILED);
}
}
else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":arrange success: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.name % ap.bed_idx % (plate_to_slice-1);
real_duplicate_count ++;
}
partplate_list.postprocess_bed_index_for_current_plate(ap);
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": arrange selected %4%: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
}
if (duplicate_single_object && (real_duplicate_count <= 0))
{
BOOST_LOG_TRIVIAL(error) << "no object can be placed under single object mode." << std::endl;
record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED]);
flush_and_exit(CLI_OBJECT_ARRANGE_FAILED);
}
//BBS: adjust the bed_index, create new plates, get the max bed_index
for (ArrangePolygon& ap : unselected)
{
if (ap.is_virt_object)
continue;
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange unselected %4%: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
}
for (ArrangePolygon& ap : locked_aps)
{
bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
partplate_list.postprocess_arrange_polygon(ap, false);
ap.apply();
}
// Apply the arrange result to all selected objects
for (ArrangePolygon& ap : selected) {
//BBS: partplate postprocess
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
}
// Apply the arrange result to unselected objects(due to the sukodu-style column changes, the position of unselected may also be modified)
for (ArrangePolygon& ap : unselected)
{
if (ap.is_virt_object)
continue;
//BBS: partplate postprocess
partplate_list.postprocess_arrange_polygon(ap, false);
ap.apply();
}
// Move the unprintable items to the last virtual bed.
// Note ap.apply() moves relatively according to bed_idx, so we need to subtract the orignal bed_idx
for (ArrangePolygon& ap : unprintable)
{
ap.bed_idx = bed_idx_max + 1;
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange m_unprintable: name: %4%, bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
}
partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1);
}
// Apply the arrange result to all selected objects
for (ArrangePolygon &ap : selected) {
//BBS: partplate postprocess
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
}
// Move the unprintable items to the last virtual bed.
for (ArrangePolygon &ap : unprintable) {
ap.bed_idx += bed_idx_max + 1;
partplate_list.postprocess_arrange_polygon(ap, true);
ap.apply();
}
//BBS: reload all objects due to arrange
partplate_list.rebuild_plates_after_arrangement();
}
}
@ -2085,7 +2322,19 @@ int CLI::run(int argc, char **argv)
load_slice_data_dir = m_config.opt_string(opt_key);
if (export_slicedata) {
BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
else if (duplicate_count > 0)
{
BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata when set repetitions." << std::endl;
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
else if (shrink_to_new_bed)
{
BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata when shrink_to_new_bed(switch printer from small to bigger." << std::endl;
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
} else if (opt_key == "export_settings") {
@ -2109,14 +2358,14 @@ int CLI::run(int argc, char **argv)
for (auto &model : m_models)
model.add_default_instances();
if (! this->export_models(IO::STL)) {
record_fail_reson(outfile_dir, CLI_EXPORT_STL_ERROR, 0, cli_errors[CLI_EXPORT_STL_ERROR]);
record_exit_reson(outfile_dir, CLI_EXPORT_STL_ERROR, 0, cli_errors[CLI_EXPORT_STL_ERROR]);
flush_and_exit(CLI_EXPORT_STL_ERROR);
}
} else if (opt_key == "export_obj") {
for (auto &model : m_models)
model.add_default_instances();
if (! this->export_models(IO::OBJ)) {
record_fail_reson(outfile_dir, CLI_EXPORT_OBJ_ERROR, 0, cli_errors[CLI_EXPORT_OBJ_ERROR]);
record_exit_reson(outfile_dir, CLI_EXPORT_OBJ_ERROR, 0, cli_errors[CLI_EXPORT_OBJ_ERROR]);
flush_and_exit(CLI_EXPORT_OBJ_ERROR);
}
}/* else if (opt_key == "export_amf") {
@ -2135,7 +2384,7 @@ int CLI::run(int argc, char **argv)
export_slice_data_dir = m_config.opt_string(opt_key);
if (load_slicedata) {
BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl;
record_fail_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS]);
flush_and_exit(CLI_INVALID_PARAMS);
}
} else if (opt_key == "slice") {
@ -2157,11 +2406,11 @@ int CLI::run(int argc, char **argv)
}
/*if (opt_key == "export_gcode" && printer_technology == ptSLA) {
boost::nowide::cerr << "error: cannot export G-code for an FFF configuration" << std::endl;
record_fail_reson(outfile_dir, 1, 0, cli_errors[1]);
record_exit_reson(outfile_dir, 1, 0, cli_errors[1]);
flush_and_exit(1);
} else if (opt_key == "export_sla" && printer_technology == ptFFF) {
boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl;
record_fail_reson(outfile_dir, 1, 0, cli_errors[1]);
record_exit_reson(outfile_dir, 1, 0, cli_errors[1]);
flush_and_exit(1);
}*/
BOOST_LOG_TRIVIAL(info) << "Need to slice for plate "<<plate_to_slice <<", total plate count "<<partplate_list.get_plate_count()<<" partplates!" << std::endl;
@ -2228,7 +2477,7 @@ int CLI::run(int argc, char **argv)
if (count == 0) {
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl;
record_fail_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS]);
record_exit_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS]);
flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
}
else if ((plate_to_slice != 0) || pre_check) {
@ -2269,7 +2518,7 @@ int CLI::run(int argc, char **argv)
if (i->print_volume_state == ModelInstancePVS_Partly_Outside)
{
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Found Object " << model_object->name <<" partly inside, can not be sliced." << std::endl;
record_fail_reson(outfile_dir, CLI_OBJECTS_PARTLY_INSIDE, index+1, cli_errors[CLI_OBJECTS_PARTLY_INSIDE]);
record_exit_reson(outfile_dir, CLI_OBJECTS_PARTLY_INSIDE, index+1, cli_errors[CLI_OBJECTS_PARTLY_INSIDE]);
flush_and_exit(CLI_OBJECTS_PARTLY_INSIDE);
}
else if ((max_triangle_count_per_plate != 0) && (i->print_volume_state == ModelInstancePVS_Inside))
@ -2283,7 +2532,7 @@ int CLI::run(int argc, char **argv)
if (triangle_count > max_triangle_count_per_plate)
{
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": triangle count " << triangle_count <<" exceeds the limit:" << max_triangle_count_per_plate;
record_fail_reson(outfile_dir, CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT, index+1, cli_errors[CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT]);
record_exit_reson(outfile_dir, CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT, index+1, cli_errors[CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT]);
flush_and_exit(CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT);
}
}
@ -2296,7 +2545,7 @@ int CLI::run(int argc, char **argv)
if (printable_instances == 0) {
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, after skipping "<<skipped_count<<" objects."<< std::endl;
record_fail_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP]);
record_exit_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP]);
flush_and_exit(CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP);
}
}
@ -2334,7 +2583,7 @@ int CLI::run(int argc, char **argv)
validate_error = CLI_VALIDATE_ERROR;
break;
}
record_fail_reson(outfile_dir, validate_error, index+1, cli_errors[validate_error]);
record_exit_reson(outfile_dir, validate_error, index+1, cli_errors[validate_error]);
flush_and_exit(validate_error);
}
else if (!warning.string.empty())
@ -2342,7 +2591,7 @@ int CLI::run(int argc, char **argv)
if (print->empty()) {
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply." << std::endl;
record_fail_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS]);
record_exit_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS]);
flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
}
else {
@ -2410,7 +2659,7 @@ int CLI::run(int argc, char **argv)
std::string conflict_result = dynamic_cast<Print *>(print)->get_conflict_string();
if (!conflict_result.empty()) {
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": found slicing result conflict!"<< std::endl;
record_fail_reson(outfile_dir, CLI_GCODE_PATH_CONFLICTS, index+1, cli_errors[CLI_GCODE_PATH_CONFLICTS]);
record_exit_reson(outfile_dir, CLI_GCODE_PATH_CONFLICTS, index+1, cli_errors[CLI_GCODE_PATH_CONFLICTS]);
flush_and_exit(CLI_GCODE_PATH_CONFLICTS);
}
// The outfile is processed by a PlaceholderParser.
@ -2435,7 +2684,7 @@ int CLI::run(int argc, char **argv)
/*if (outfile != outfile_final) {
if (Slic3r::rename_file(outfile, outfile_final)) {
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
record_fail_reson(outfile_dir, 1, index+1, cli_errors[1]);
record_exit_reson(outfile_dir, 1, index+1, cli_errors[1]);
flush_and_exit(1);
}
outfile = outfile_final;
@ -2460,7 +2709,7 @@ int CLI::run(int argc, char **argv)
export_slicedata_error = true;
if (fs::exists(plate_dir))
fs::remove_all(plate_dir);
record_fail_reson(outfile_dir, ret, index+1, cli_errors[ret]);
record_exit_reson(outfile_dir, ret, index+1, cli_errors[ret]);
flush_and_exit(ret);
}
}
@ -2470,7 +2719,7 @@ int CLI::run(int argc, char **argv)
if (time_cost > max_slicing_time_per_plate) {
BOOST_LOG_TRIVIAL(error) << boost::format("plate %1%'s slice time %2% exceeds the limit %3%, return error.")
%(index+1) %time_cost %max_slicing_time_per_plate;
record_fail_reson(outfile_dir, CLI_SLICING_TIME_EXCEEDS_LIMIT, index+1, cli_errors[CLI_SLICING_TIME_EXCEEDS_LIMIT]);
record_exit_reson(outfile_dir, CLI_SLICING_TIME_EXCEEDS_LIMIT, index+1, cli_errors[CLI_SLICING_TIME_EXCEEDS_LIMIT]);
flush_and_exit(CLI_SLICING_TIME_EXCEEDS_LIMIT);
}
}
@ -2478,7 +2727,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate "<<index+1 << std::endl;
boost::nowide::cerr << ex.what() << std::endl;
//continue;
record_fail_reson(outfile_dir, CLI_SLICING_ERROR, index+1, cli_errors[CLI_SLICING_ERROR]);
record_exit_reson(outfile_dir, CLI_SLICING_ERROR, index+1, cli_errors[CLI_SLICING_ERROR]);
flush_and_exit(CLI_SLICING_ERROR);
}
}
@ -2528,7 +2777,7 @@ int CLI::run(int argc, char **argv)
}
} else {
boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl;
record_fail_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION]);
record_exit_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION]);
flush_and_exit(CLI_UNSUPPORTED_OPERATION);
}
}
@ -3048,7 +3297,7 @@ int CLI::run(int argc, char **argv)
calibration_thumbnails, plate_bboxes, &m_print_config))
{
release_PlateData_list(plate_data_list);
record_fail_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR]);
record_exit_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR]);
flush_and_exit(CLI_EXPORT_3MF_ERROR);
}
release_PlateData_list(plate_data_list);
@ -3085,6 +3334,15 @@ int CLI::run(int argc, char **argv)
}
//BBS: flush logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl;
//record the duplicate here
if ((duplicate_count > 0) && duplicate_single_object)
{
record_exit_reson(outfile_dir, 0, plate_to_slice, cli_errors[0], real_duplicate_count);
}
else
record_exit_reson(outfile_dir, 0, plate_to_slice, cli_errors[0]);
boost::nowide::cout.flush();
boost::nowide::cerr.flush();

View File

@ -1432,6 +1432,92 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
return plate_extruders;
}
std::vector<int> PartPlate::get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const
{
std::vector<int> plate_extruders;
// if 3mf file
int glb_support_intf_extr = full_config.opt_int("support_interface_filament");
int glb_support_extr = full_config.opt_int("support_filament");
bool glb_support = full_config.opt_bool("enable_support");
glb_support |= full_config.opt_int("raft_layers") > 0;
for (std::set<std::pair<int, int>>::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];
for (ModelVolume* mv : object->volumes) {
std::vector<int> volume_extruders = mv->get_extruders();
plate_extruders.insert(plate_extruders.end(), volume_extruders.begin(), volume_extruders.end());
}
// layer range
for (auto layer_range : object->layer_config_ranges) {
if (layer_range.second.has("extruder")) {
if (auto id = layer_range.second.option("extruder")->getInt(); id > 0)
plate_extruders.push_back(id);
}
}
bool obj_support = false;
const ConfigOption* obj_support_opt = object->config.option("enable_support");
const ConfigOption *obj_raft_opt = object->config.option("raft_layers");
if (obj_support_opt != nullptr || obj_raft_opt != nullptr) {
if (obj_support_opt != nullptr)
obj_support = obj_support_opt->getBool();
if (obj_raft_opt != nullptr)
obj_support |= obj_raft_opt->getInt() > 0;
}
else
obj_support = glb_support;
if (!obj_support)
continue;
int obj_support_intf_extr = 0;
const ConfigOption* support_intf_extr_opt = object->config.option("support_interface_filament");
if (support_intf_extr_opt != nullptr)
obj_support_intf_extr = support_intf_extr_opt->getInt();
if (obj_support_intf_extr != 0)
plate_extruders.push_back(obj_support_intf_extr);
else if (glb_support_intf_extr != 0)
plate_extruders.push_back(glb_support_intf_extr);
int obj_support_extr = 0;
const ConfigOption* support_extr_opt = object->config.option("support_filament");
if (support_extr_opt != nullptr)
obj_support_extr = support_extr_opt->getInt();
if (obj_support_extr != 0)
plate_extruders.push_back(obj_support_extr);
else if (glb_support_extr != 0)
plate_extruders.push_back(glb_support_extr);
}
}
if (conside_custom_gcode) {
//BBS
int nums_extruders = 0;
if (const ConfigOptionStrings *color_option = dynamic_cast<const ConfigOptionStrings *>(full_config.option("filament_colour"))) {
nums_extruders = color_option->values.size();
if (m_model->plates_custom_gcodes.find(m_plate_index) != m_model->plates_custom_gcodes.end()) {
for (auto item : m_model->plates_custom_gcodes.at(m_plate_index).gcodes) {
if (item.type == CustomGCode::Type::ToolChange && item.extruder <= nums_extruders)
plate_extruders.push_back(item.extruder);
}
}
}
}
std::sort(plate_extruders.begin(), plate_extruders.end());
auto it_end = std::unique(plate_extruders.begin(), plate_extruders.end());
plate_extruders.resize(std::distance(plate_extruders.begin(), it_end));
return plate_extruders;
}
std::vector<int> PartPlate::get_extruders_without_support(bool conside_custom_gcode) const
{
std::vector<int> plate_extruders;
@ -2018,6 +2104,36 @@ void PartPlate::translate_all_instance(Vec3d position)
return;
}
void PartPlate::duplicate_all_instance(unsigned int dup_count)
{
std::set<std::pair<int, int>> old_obj_list = obj_to_instance_set;
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": plate_id %1%, dup_count %2%") % m_plate_index % dup_count;
for (std::set<std::pair<int, int>>::iterator it = old_obj_list.begin(); it != old_obj_list.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];
for (size_t index = 0; index < dup_count; index ++)
{
ModelObject* newObj = m_model->add_object(*object);
newObj->name = object->name +"_"+ std::to_string(index+1);
int new_obj_id = m_model->objects.size() - 1;
for ( size_t new_instance_id = 0; new_instance_id < object->instances.size(); new_instance_id++ )
{
obj_to_instance_set.emplace(std::pair(new_obj_id, new_instance_id));
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": duplicate object into plate: index_pair [%1%,%2%], obj_id %3%") % new_obj_id % new_instance_id % newObj->id().id;
}
}
}
}
return;
}
//update instance exclude state
void PartPlate::update_instance_exclude_status(int obj_id, int instance_id, BoundingBoxf3* bounding_box)
@ -4491,15 +4607,15 @@ bool PartPlateList::is_all_slice_results_ready_for_print() const
for (unsigned int i = 0; i < (unsigned int) m_plate_list.size(); ++i) {
if (!m_plate_list[i]->empty()) {
if (m_plate_list[i]->is_all_instances_unprintable()) {
continue;
if (m_plate_list[i]->is_all_instances_unprintable()) {
continue;
}
if (!m_plate_list[i]->is_slice_result_ready_for_print()) {
return false;
if (!m_plate_list[i]->is_slice_result_ready_for_print()) {
return false;
}
}
if (m_plate_list[i]->is_slice_result_ready_for_print()) {
res = true;
if (m_plate_list[i]->is_slice_result_ready_for_print()) {
res = true;
}
}

View File

@ -263,7 +263,7 @@ public:
// set the plate's name
void set_plate_name(const std::string &name);
//get the print's object, result and index
void get_print(PrintBase **print, GCodeResult **result, int *index);
@ -289,6 +289,7 @@ public:
Vec3d get_origin() { return m_origin; }
Vec3d estimate_wipe_tower_size(const double w, const double wipe_volume) const;
std::vector<int> get_extruders(bool conside_custom_gcode = false) const;
std::vector<int> get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const;
std::vector<int> get_extruders_without_support(bool conside_custom_gcode = false) const;
std::vector<int> get_used_extruders();
@ -317,6 +318,9 @@ public:
//translate instance on the plate
void translate_all_instance(Vec3d position);
//duplicate all instance for count
void duplicate_all_instance(unsigned int dup_count);
//update instance exclude state
void update_instance_exclude_status(int obj_id, int instance_id, BoundingBoxf3* bounding_box = nullptr);
@ -403,7 +407,7 @@ public:
{
bool result = m_slice_result_valid;
if (result)
result = m_gcode_result ? (!m_gcode_result->toolpath_outside) : false;// && !m_gcode_result->conflict_result.has_value() gcode conflict can also print
result = m_gcode_result ? (!m_gcode_result->toolpath_outside) : false;// && !m_gcode_result->conflict_result.has_value() gcode conflict can also print
return result;
}