FIX: rewrite per-object printing order logic

1. Previous logic can't guarantee left-to-right printing order, so
   toolhead may crash on the right side. In the new algorithm printing
   order is guaranteed.
2. Clearance radius should be the max of 3 directions (left, bottom,
   up), not including right, otherwise collision may happen on bottom or
   up directions.
3. Add is_extrusion_cali_object property to handle extrusion brim
   overlap better.

Change-Id: I44868b9925d983f5cca0c31d35dfa28d895fadbf
This commit is contained in:
Arthur Tang 2022-10-22 23:31:02 +08:00 committed by Lane.Wei
parent 59dfcb98fc
commit 5544e9602c
9 changed files with 97 additions and 24 deletions

View File

@ -111,7 +111,8 @@
"0.08" "0.08"
], ],
"printable_height": "250", "printable_height": "250",
"extruder_clearance_radius": "32", "extruder_clearance_radius": "57",
"extruder_clearance_max_radius": "68",
"extruder_clearance_height_to_rod": "36", "extruder_clearance_height_to_rod": "36",
"extruder_clearance_height_to_lid": "140", "extruder_clearance_height_to_lid": "140",
"nozzle_volume": "118", "nozzle_volume": "118",

View File

@ -52,6 +52,7 @@ struct ArrangePolygon {
//BBS: add locked_plate to indicate whether it is in the locked plate //BBS: add locked_plate to indicate whether it is in the locked plate
int locked_plate{ -1 }; int locked_plate{ -1 };
bool is_virt_object{ false }; bool is_virt_object{ false };
bool is_extrusion_cali_object{ false };
bool is_wipe_tower{false}; bool is_wipe_tower{false};
//BBS: add row/col for sudoku-style layout //BBS: add row/col for sudoku-style layout
int row{0}; int row{0};

View File

@ -759,7 +759,7 @@ static std::vector<std::string> s_Preset_printer_options {
"printer_technology", "printer_technology",
"printable_area", "bed_exclude_area", "gcode_flavor", "printable_area", "bed_exclude_area", "gcode_flavor",
"single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "change_filament_gcode", "single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "change_filament_gcode",
"printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_max_radius","extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"default_print_profile", "inherits", "default_print_profile", "inherits",
"silent_mode", "silent_mode",
// BBS // BBS

View File

@ -80,6 +80,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"extruder_clearance_height_to_rod", "extruder_clearance_height_to_rod",
"extruder_clearance_height_to_lid", "extruder_clearance_height_to_lid",
"extruder_clearance_radius", "extruder_clearance_radius",
"extruder_clearance_max_radius",
"extruder_colour", "extruder_colour",
"extruder_offset", "extruder_offset",
"filament_flow_ratio", "filament_flow_ratio",
@ -389,6 +390,8 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
const PrintInstance *print_instance; const PrintInstance *print_instance;
BoundingBox bounding_box; BoundingBox bounding_box;
Polygon hull_polygon; Polygon hull_polygon;
int index;
double arrange_score;
}; };
std::vector<struct print_instance_info> print_instance_with_bounding_box; std::vector<struct print_instance_info> print_instance_with_bounding_box;
{ {
@ -480,22 +483,71 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
} }
} }
//sort the print instance // calc sort order
auto bed_points = get_bed_shape(print_config);
float bed_width = bed_points[1].x() - bed_points[0].x();
// 如果扩大以后的多边形的距离小于这个值,就需要严格保证从左到右的打印顺序,否则会撞工具头右侧
float unsafe_dist = scale_(print_config.extruder_clearance_max_radius.value - print_config.extruder_clearance_radius.value);
std::vector<Vec2i> left_right_pair; // pairs in this vector must strictly obey the left-right order
for (size_t i = 0; i < print_instance_with_bounding_box.size();i++) {
auto &inst = print_instance_with_bounding_box[i];
inst.index = i;
Point pt = inst.bounding_box.center();
inst.arrange_score = pt.x() / 2 + pt.y(); // we prefer print row-by-row, so cost on x-direction is smaller
}
for (size_t i = 0; i < print_instance_with_bounding_box.size(); i++) {
auto &inst = print_instance_with_bounding_box[i];
for (size_t j = 0; j < print_instance_with_bounding_box.size(); j++) {
if (j != i) {
auto &l = print_instance_with_bounding_box[i];
auto &r = print_instance_with_bounding_box[j];
auto ly1 = l.bounding_box.min.y();
auto ly2 = l.bounding_box.max.y();
auto ry1 = r.bounding_box.min.y();
auto ry2 = r.bounding_box.max.y();
auto lx1 = l.bounding_box.min.x();
auto rx1 = r.bounding_box.min.x();
auto lx2 = l.bounding_box.max.x();
auto rx2 = r.bounding_box.max.x();
auto inter_min = std::max(ly1, ry1);
auto inter_max = std::min(ly2, ry2);
auto inter_y = inter_max - inter_min;
inter_min = std::max(lx1, rx1);
inter_max = std::min(lx2, rx2);
auto inter_x = inter_max - inter_min;
// 如果y方向有重合说明两个物体在一行应该先打左边的物体即先比较二者的x坐标。
if (inter_y > 0) {
if (std::max(rx1 - lx2, lx1 - rx2) < unsafe_dist) {
std::string dir = "left";
if (lx1 > rx1) {
left_right_pair.emplace_back(j, i);
print_instance_with_bounding_box[i].arrange_score = std::max(inst.arrange_score, r.arrange_score + bed_width);
} else {
left_right_pair.emplace_back(i, j);
print_instance_with_bounding_box[j].arrange_score = std::max(r.arrange_score, l.arrange_score + bed_width);
dir = "right";
}
BOOST_LOG_TRIVIAL(debug) << "print_instance " << inst.print_instance->model_instance->get_object()->name
<< ", right=" << r.print_instance->model_instance->get_object()->name << ", l.score: " << l.arrange_score
<< ", r.score: " << r.arrange_score << ", dist:" << std::max(rx1 - lx2, lx1 - rx2) << ", dir: " << dir;
}
}
}
}
}
BOOST_LOG_TRIVIAL(debug) << "bed width: " << bed_width << ", unsafe_dist:" << unsafe_dist;
for (auto& inst:print_instance_with_bounding_box) {
BOOST_LOG_TRIVIAL(debug) << "print_instance " << inst.print_instance->model_instance->get_object()->name
<< ", score: " << inst.arrange_score;
}
// sort the print instance
std::sort(print_instance_with_bounding_box.begin(), print_instance_with_bounding_box.end(), std::sort(print_instance_with_bounding_box.begin(), print_instance_with_bounding_box.end(),
[](auto &l, auto &r) { [&left_right_pair](print_instance_info& l, print_instance_info& r) {
auto ly1 = l.bounding_box.min.y(); if (std::find(left_right_pair.begin(),left_right_pair.end(), Vec2i(l.index, r.index)) != left_right_pair.end())
auto ly2 = l.bounding_box.max.y(); return true;
auto ry1 = r.bounding_box.min.y(); else
auto ry2 = r.bounding_box.max.y(); return l.arrange_score < r.arrange_score;});
auto inter_min = std::max(ly1, ry1);
auto inter_max = std::min(ly2, ry2);
auto lx = l.bounding_box.min.x();
auto rx = r.bounding_box.min.x();
if (inter_max - inter_min > 0)
return (lx < rx) || ((lx == rx) && (ly1 < ry1));
else
return (ly1 < ry1);
});
// sequential_print_vertical_clearance_valid // sequential_print_vertical_clearance_valid
{ {

View File

@ -992,6 +992,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(40)); def->set_default_value(new ConfigOptionFloat(40));
def = this->add("extruder_clearance_max_radius", coFloat);
def->label = L("Max Radius");
def->tooltip = L("Max clearance radius around extruder. Used as input of auto-arranging to avoid collision when printing by object");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(68));
def = this->add("extruder_colour", coStrings); def = this->add("extruder_colour", coStrings);
def->label = L("Extruder Color"); def->label = L("Extruder Color");
def->tooltip = L("Only used as a visual help on UI"); def->tooltip = L("Only used as a visual help on UI");

View File

@ -824,6 +824,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, extruder_clearance_height_to_rod))//BBs ((ConfigOptionFloat, extruder_clearance_height_to_rod))//BBs
((ConfigOptionFloat, extruder_clearance_height_to_lid))//BBS ((ConfigOptionFloat, extruder_clearance_height_to_lid))//BBS
((ConfigOptionFloat, extruder_clearance_radius)) ((ConfigOptionFloat, extruder_clearance_radius))
((ConfigOptionFloat, extruder_clearance_max_radius))
((ConfigOptionStrings, extruder_colour)) ((ConfigOptionStrings, extruder_colour))
((ConfigOptionPoints, extruder_offset)) ((ConfigOptionPoints, extruder_offset))
((ConfigOptionBools, reduce_fan_stop_start_freq)) ((ConfigOptionBools, reduce_fan_stop_start_freq))

View File

@ -503,6 +503,9 @@ void ArrangeJob::process()
if (params.is_seq_print) if (params.is_seq_print)
params.min_obj_distance = std::max(params.min_obj_distance, scaled(params.cleareance_radius)); params.min_obj_distance = std::max(params.min_obj_distance, scaled(params.cleareance_radius));
if (params.avoid_extrusion_cali_region && print.full_print_config().opt_bool("scan_first_layer"))
m_plater->get_partplate_list().preprocess_nonprefered_areas(m_unselected, MAX_NUM_PLATES);
double skirt_distance = print.has_skirt() ? print.config().skirt_distance.value : 0; double skirt_distance = print.has_skirt() ? print.config().skirt_distance.value : 0;
double brim_max = 0; double brim_max = 0;
std::for_each(m_selected.begin(), m_selected.end(), [&](ArrangePolygon ap) { brim_max = std::max(brim_max, ap.brim_width); }); std::for_each(m_selected.begin(), m_selected.end(), [&](ArrangePolygon ap) { brim_max = std::max(brim_max, ap.brim_width); });
@ -514,21 +517,26 @@ void ArrangeJob::process()
params.bed_shrink_y = settings.bed_shrink_y + params.brim_skirt_distance; params.bed_shrink_y = settings.bed_shrink_y + params.brim_skirt_distance;
// for sequential print, we need to inflate the bed because cleareance_radius is so large // for sequential print, we need to inflate the bed because cleareance_radius is so large
if (params.is_seq_print) { if (params.is_seq_print) {
params.bed_shrink_x -= params.cleareance_radius/2; float shift_dist = params.cleareance_radius / 2 - 5;
params.bed_shrink_y -= params.cleareance_radius/2; params.bed_shrink_x -= shift_dist;
params.bed_shrink_y -= shift_dist;
// dont forget to move the excluded region // dont forget to move the excluded region
for (auto& region : m_unselected) { for (auto& region : m_unselected) {
if (region.is_virt_object) if (region.is_virt_object)
region.poly.translate(-scaled(params.cleareance_radius/2), -scaled(params.cleareance_radius/2)); region.poly.translate(-scaled(shift_dist), -scaled(shift_dist));
} }
} }
// do not inflate brim_width. Objects are allowed to have overlapped brim. // do not inflate brim_width. Objects are allowed to have overlapped brim.
std::for_each(m_selected.begin(), m_selected.end(), [&](auto& ap) {ap.inflation = params.min_obj_distance / 2; }); std::for_each(m_selected.begin(), m_selected.end(), [&](auto& ap) {ap.inflation = params.min_obj_distance / 2; });
std::for_each(m_unselected.begin(), m_unselected.end(), [&](auto& ap) {ap.inflation = ap.is_virt_object ? scaled(params.brim_skirt_distance) : params.min_obj_distance / 2; }); // For occulusion regions, inflation should be larger to prevent genrating brim on them.
// However, extrusion cali regions are exceptional, since we can allow brim overlaps them.
std::for_each(m_unselected.begin(), m_unselected.end(), [&](auto &ap) {
ap.inflation = !ap.is_virt_object ?
params.min_obj_distance / 2 :
(ap.is_extrusion_cali_object ? scaled(params.cleareance_radius / 2) : scaled(params.brim_skirt_distance + params.cleareance_radius / 2));
});
if (params.avoid_extrusion_cali_region && print.full_print_config().opt_bool("scan_first_layer"))
m_plater->get_partplate_list().preprocess_nonprefered_areas(m_unselected, MAX_NUM_PLATES);
m_plater->get_partplate_list().preprocess_exclude_areas(params.excluded_regions, 1); m_plater->get_partplate_list().preprocess_exclude_areas(params.excluded_regions, 1);

View File

@ -3461,6 +3461,7 @@ bool PartPlateList::preprocess_nonprefered_areas(arrangement::ArrangePolygons& r
ret.translation = Vec2crd(0, 0); ret.translation = Vec2crd(0, 0);
ret.rotation = 0.0f; ret.rotation = 0.0f;
ret.is_virt_object = true; ret.is_virt_object = true;
ret.is_extrusion_cali_object = true;
ret.bed_idx = j; ret.bed_idx = j;
ret.height = 1; ret.height = 1;
ret.name = "NonpreferedRegion" + std::to_string(index); ret.name = "NonpreferedRegion" + std::to_string(index);

View File

@ -2001,7 +2001,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
//BBS: add bed_exclude_area //BBS: add bed_exclude_area
, config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({
"printable_area", "bed_exclude_area", "print_sequence", "printable_area", "bed_exclude_area", "print_sequence",
"extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "skirt_loops", "skirt_distance", "extruder_clearance_radius", "extruder_clearance_max_radius",
"extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "skirt_loops", "skirt_distance",
"brim_width", "brim_object_gap", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "brim_width", "brim_object_gap", "brim_type", "nozzle_diameter", "single_extruder_multi_material",
"enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_volume", "enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_volume",
"extruder_colour", "filament_colour", "material_colour", "printable_height", "printer_model", "printer_technology", "extruder_colour", "filament_colour", "material_colour", "printable_height", "printer_model", "printer_technology",