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:
parent
59dfcb98fc
commit
5544e9602c
|
@ -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",
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue