ENH: CLI: add more logic to support repetitions

1. add identify_id for those clone objects
2. ensure succuss when copy multiple objects

Change-Id: I8a92f485442577ce70b1f5c46449dae1ae07b713
This commit is contained in:
lane.wei 2023-08-03 16:22:00 +08:00 committed by Lane.Wei
parent 468fc828d0
commit db5ed65577
2 changed files with 460 additions and 338 deletions

View file

@ -1805,33 +1805,32 @@ int CLI::run(int argc, char **argv)
partplate_list.set_shapes(current_printable_area, current_exclude_area, bed_texture, height_to_lid, height_to_rod); 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(); //plate_stride = partplate_list.plate_stride_x();
} }
if (plate_data_src.size() > 0)
{ 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) {
partplate_list.load_from_3mf_structure(plate_data_src);
//BBS: translate old 3mf to correct positions //BBS: translate old 3mf to correct positions
if (translate_old) { if (translate_old) {
//translate the objects //translate the objects
int plate_count = partplate_list.get_plate_count(); int plate_count = plate_list.get_plate_count();
for (int index = 1; index < plate_count; index ++) { for (int index = 1; index < plate_count; index ++) {
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index); Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index);
Vec3d cur_origin = cur_plate->get_origin(); Vec3d cur_origin = cur_plate->get_origin();
Vec3d new_origin = partplate_list.compute_origin_using_new_size(index, old_printable_width, old_printable_depth); 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); 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; 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;
partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true); plate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true);
} }
if (shrink_to_new_bed) if (shrink_to_new_bed)
{ {
int plate_count = partplate_list.get_plate_count(); int plate_count = plate_list.get_plate_count();
for (int index = 0; index < plate_count; index ++) { for (int index = 0; index < plate_count; index ++) {
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index); Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index);
Vec3d cur_origin = cur_plate->get_origin(); Vec3d cur_origin = cur_plate->get_origin();
Vec3d new_origin = partplate_list.compute_origin_using_new_size(index, current_printable_width, current_printable_depth); 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_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 cur_center = cur_origin + cur_center_offset;
Vec3d new_center = new_origin + new_center_offset; Vec3d new_center = new_origin + new_center_offset;
@ -1841,8 +1840,14 @@ int CLI::run(int argc, char **argv)
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, 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; 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;
partplate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); 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);
} }
/*for (ModelObject *model_object : m_models[0].objects) /*for (ModelObject *model_object : m_models[0].objects)
@ -1902,10 +1907,7 @@ int CLI::run(int argc, char **argv)
record_exit_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); flush_and_exit(CLI_INVALID_PARAMS);
} }
BOOST_LOG_TRIVIAL(info) << "repetitions value " << repetitions_count << ", will copy model object first\n"; BOOST_LOG_TRIVIAL(info) << "repetitions value " << repetitions_count << std::endl;
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_skip, skip_maps);
need_arrange = true; need_arrange = true;
duplicate_count = repetitions_count - 1; duplicate_count = repetitions_count - 1;
@ -2154,8 +2156,43 @@ int CLI::run(int argc, char **argv)
if (m_models.size() > 0) if (m_models.size() > 0)
{ {
Model &model = m_models[0]; Model &model = m_models[0];
Model original_model;
std::set<std::pair<int, int>> backup_set;
bool finished_arrange = false, first_run = true;
Slic3r::GUI::PartPlate* cur_plate;
int low_duplicate_count = 0, up_duplicate_count = duplicate_count, arrange_count = 0;
arrange_cfg.is_seq_print = false; arrange_cfg.is_seq_print = false;
if (duplicate_count > 0) {
original_model = model;
}
while(!finished_arrange)
{
arrange_count++;
//step-0: duplicate model
if (duplicate_count > 0)
{
//copy model objects and instances on plate
if (!first_run) {
BOOST_LOG_TRIVIAL(info) << boost::format("restore model object and plate, new duplicate_count %1%, arrange_count=%2%")%duplicate_count%arrange_count;
beds = get_bed_shape(m_print_config);
model.clear_objects();
model.clear_materials();
model = original_model;
partplate_list.load_from_3mf_structure(plate_data_src);
selected.clear();
unselected.clear();
unprintable.clear();
locked_aps.clear();
}
else
first_run = false;
cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
cur_plate->duplicate_all_instance(duplicate_count, need_skip, skip_maps);
}
//Step-1: prepare arrange polygons //Step-1: prepare arrange polygons
if (duplicate_count == 0) if (duplicate_count == 0)
@ -2199,7 +2236,7 @@ int CLI::run(int argc, char **argv)
} }
else { else {
//only arrange current plate //only arrange current plate
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1); //cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
PrintSequence curr_plate_seq = cur_plate->get_print_seq(); PrintSequence curr_plate_seq = cur_plate->get_print_seq();
if (curr_plate_seq == PrintSequence::ByDefault) { if (curr_plate_seq == PrintSequence::ByDefault) {
auto seq_print = m_print_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence"); auto seq_print = m_print_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence");
@ -2351,18 +2388,20 @@ int CLI::run(int argc, char **argv)
std::for_each(selected.begin(), selected.end(), [&](auto& ap) {ap.inflation = arrange_cfg.min_obj_distance / 2; }); std::for_each(selected.begin(), selected.end(), [&](auto& ap) {ap.inflation = arrange_cfg.min_obj_distance / 2; });
{ {
BOOST_LOG_TRIVIAL(info) << "items selected before arranging: "; BOOST_LOG_TRIVIAL(info) << boost::format("items selected before arranging: %1%")%selected.size();
for (auto selected : selected) for (auto selected : selected)
BOOST_LOG_TRIVIAL(info) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx BOOST_LOG_TRIVIAL(trace) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx
<< ", trans: " << selected.translation.transpose(); << ", trans: " << selected.translation.transpose();
} }
arrange_cfg.progressind= [](unsigned st, std::string str = "") { arrange_cfg.progressind= [](unsigned st, std::string str = "") {
boost::nowide::cout << "st=" << st << ", " << str << std::endl; //boost::nowide::cout << "st=" << st << ", " << str << std::endl;
}; };
//Step-3:do the arrange //Step-3:do the arrange
BOOST_LOG_TRIVIAL(info) << boost::format("start %1% th arranging...")%arrange_count;
arrangement::arrange(selected, unselected, beds, arrange_cfg); arrangement::arrange(selected, unselected, beds, arrange_cfg);
arrangement::arrange(unprintable, {}, beds, arrange_cfg); arrangement::arrange(unprintable, {}, beds, arrange_cfg);
BOOST_LOG_TRIVIAL(info) << boost::format("finished %1% th arranging...")%arrange_count;
//Step-4:postprocess by partplate list&&apply the result //Step-4:postprocess by partplate list&&apply the result
int bed_idx_max = 0; int bed_idx_max = 0;
@ -2377,7 +2416,7 @@ int CLI::run(int argc, char **argv)
partplate_list.postprocess_bed_index_for_selected(ap); partplate_list.postprocess_bed_index_for_selected(ap);
bed_idx_max = std::max(ap.bed_idx, bed_idx_max); 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"; BOOST_LOG_TRIVIAL(trace)<< "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) { for (ArrangePolygon &ap : locked_aps) {
bed_idx_max = std::max(ap.bed_idx, bed_idx_max); bed_idx_max = std::max(ap.bed_idx, bed_idx_max);
@ -2411,7 +2450,7 @@ int CLI::run(int argc, char **argv)
partplate_list.clear(false, false, true, plate_to_slice-1); partplate_list.clear(false, false, true, plate_to_slice-1);
//BBS: adjust the bed_index, create new plates, get the max bed_index //BBS: adjust the bed_index, create new plates, get the max bed_index
bool failed_this_time = false;
for (ArrangePolygon& ap : selected) { for (ArrangePolygon& ap : selected) {
if (ap.bed_idx != (plate_to_slice-1)) if (ap.bed_idx != (plate_to_slice-1))
{ {
@ -2419,9 +2458,32 @@ int CLI::run(int argc, char **argv)
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); 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) if (!duplicate_single_object)
{ {
BOOST_LOG_TRIVIAL(error) << "arrange failed when duplicate multiple objects." << std::endl; BOOST_LOG_TRIVIAL(warning) << boost::format("arrange failed when duplicate multiple objects at count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED]);
flush_and_exit(CLI_OBJECT_ARRANGE_FAILED); if (duplicate_count == 1)
{
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": failed even on duplicate 1 copy, just print one original model");
duplicate_count = 0;
}
else
{
if (duplicate_count == low_duplicate_count)
{
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": previous success, but currently failed count %1%!!!")%duplicate_count;
up_duplicate_count = duplicate_count;
low_duplicate_count --;
duplicate_count --;
}
else {
up_duplicate_count = duplicate_count;
duplicate_count = (up_duplicate_count + low_duplicate_count)/2;
}
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": try new count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
}
//record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED]);
//flush_and_exit(CLI_OBJECT_ARRANGE_FAILED);
failed_this_time = true;
break;
} }
} }
else { else {
@ -2434,11 +2496,49 @@ int CLI::run(int argc, char **argv)
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; 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)) if (failed_this_time) {
if (duplicate_count == 0)
{ {
BOOST_LOG_TRIVIAL(error) << "no object can be placed under single object mode." << std::endl; //restore to the original
record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED]); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": restore to the original model and plates");
flush_and_exit(CLI_OBJECT_ARRANGE_FAILED); finished_arrange = true;
model = original_model;
partplate_list.load_from_3mf_structure(plate_data_src);
translate_models(partplate_list);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process");
}
continue;
}
if (duplicate_single_object)
{
if (real_duplicate_count <= 0) {
BOOST_LOG_TRIVIAL(warning) << "no object can be placed under single object mode, restore to the original model and plates also" << 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);
finished_arrange = true;
model = original_model;
partplate_list.load_from_3mf_structure(plate_data_src);
translate_models(partplate_list);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process");
continue;
}
}
else {
//multiple objects case
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": multiple objects mode, arrange success on count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
if ((duplicate_count == up_duplicate_count) || (duplicate_count == (up_duplicate_count - 1)))
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found the max arrangeable count %1%")%duplicate_count;
}
else {
low_duplicate_count = duplicate_count;
duplicate_count = (up_duplicate_count + low_duplicate_count)/2;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": try new count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
continue;
}
} }
//BBS: adjust the bed_index, create new plates, get the max bed_index //BBS: adjust the bed_index, create new plates, get the max bed_index
@ -2493,6 +2593,10 @@ int CLI::run(int argc, char **argv)
partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1); partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1);
} }
finished_arrange = true;
}
original_model.clear_objects();
original_model.clear_materials();
} }
} }
@ -3533,7 +3637,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl;
//record the duplicate here //record the duplicate here
if ((duplicate_count > 0) && duplicate_single_object) if (duplicate_count > 0)
{ {
std::map<std::string, std::string> key_values; std::map<std::string, std::string> key_values;
key_values["sliced_count"] = std::to_string(real_duplicate_count); key_values["sliced_count"] = std::to_string(real_duplicate_count);

View file

@ -2146,6 +2146,24 @@ void PartPlate::duplicate_all_instance(unsigned int dup_count, bool need_skip, s
} }
} }
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];
ModelInstance* instance = object->instances[instance_id];
if (instance->printable)
{
instance->loaded_id = instance->id().id;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": set obj %1% instance %2%'s loaded_id to its id %3%, name %4%") % obj_id %instance_id %instance->loaded_id % object->name;
}
}
}
return; return;
} }