From c07a7fd2fc42673888e087e398af2139735987d3 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 9 Jan 2019 22:07:24 +0100 Subject: [PATCH 1/4] brim ears - add brim_ears setting: bool: set to true to activate this new funtino - add brim_ears_max_angle : float : max angle for a corner to be assigned a brim ear. --- lib/Slic3r/GUI/PresetEditor.pm | 7 +- slic3r.pl | 2 + src/GUI/Dialogs/PresetEditor.hpp | 2 +- xs/src/libslic3r/Print.cpp | 125 +++++++++++++++++++++++++++++++ xs/src/libslic3r/PrintConfig.cpp | 17 +++++ xs/src/libslic3r/PrintConfig.hpp | 4 + 6 files changed, 155 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GUI/PresetEditor.pm b/lib/Slic3r/GUI/PresetEditor.pm index 823805401a..8dd307e808 100644 --- a/lib/Slic3r/GUI/PresetEditor.pm +++ b/lib/Slic3r/GUI/PresetEditor.pm @@ -454,7 +454,7 @@ sub options { perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration default_acceleration skirts skirt_distance skirt_height min_skirt_length - brim_connections_width brim_width interior_brim_width + brim_connections_width brim_ears brim_ears_max_angle brim_width interior_brim_width support_material support_material_threshold support_material_max_layers support_material_enforce_layers raft_layers support_material_pattern support_material_spacing support_material_angle @@ -593,6 +593,8 @@ sub build { { my $optgroup = $page->new_optgroup('Brim'); $optgroup->append_single_option_line('brim_width'); + $optgroup->append_single_option_line('brim_ears'); + $optgroup->append_single_option_line('brim_ears_max_angle'); $optgroup->append_single_option_line('interior_brim_width'); $optgroup->append_single_option_line('brim_connections_width'); } @@ -949,6 +951,9 @@ sub _update { # perimeter_extruder uses the same logic as in Print::extruders() $self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim); + $self->get_field('brim_ears')->toggle($have_brim); + $self->get_field('brim_ears_max_angle')->toggle($have_brim && $config->brim_ears); + my $have_support_material = $config->support_material || $config->raft_layers > 0; my $have_support_interface = $config->support_material_interface_layers > 0; my $have_support_pillars = $have_support_material && $config->support_material_pattern eq 'pillars'; diff --git a/slic3r.pl b/slic3r.pl index 647b09ce61..18d2225a60 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -554,6 +554,8 @@ sub usage { of filament on the first layer, for each extruder (mm, 0+, default: $config->{min_skirt_length}) --brim-width Width of the brim that will get added to each object to help adhesion (mm, default: $config->{brim_width}) + --brim-ears set to true to print the brim only on sharp corners. + --brim-ears-max-angle Max angle for a corner to be assigned a brim ear. --interior-brim-width Width of the brim that will get printed inside object holes to help adhesion (mm, default: $config->{interior_brim_width}) diff --git a/src/GUI/Dialogs/PresetEditor.hpp b/src/GUI/Dialogs/PresetEditor.hpp index a6046c10bb..71c3eabda3 100644 --- a/src/GUI/Dialogs/PresetEditor.hpp +++ b/src/GUI/Dialogs/PresetEditor.hpp @@ -158,7 +158,7 @@ class PrintEditor : public PresetEditor { "perimeter_acceleration"s, "infill_acceleration"s, "bridge_acceleration"s, "first_layer_acceleration"s, "default_acceleration"s, "skirts"s, "skirt_distance"s, "skirt_height"s, "min_skirt_length"s, - "brim_connections_width"s, "brim_width"s, "interior_brim_width"s, + "brim_connections_width"s, "brim_ears"s, "brim_ears_max_angle"s, "brim_width"s, "interior_brim_width"s, "support_material"s, "support_material_threshold"s, "support_material_max_layers"s, "support_material_enforce_layers"s, "raft_layers"s, "support_material_pattern"s, "support_material_spacing"s, "support_material_angle"s, ""s, diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 239d4a32d0..c29445541a 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -349,6 +349,8 @@ Print::invalidate_state_by_config(const PrintConfigBase &config) osteps.insert(posSupportMaterial); } else if (opt_key == "brim_width" || opt_key == "interior_brim_width" + || opt_key == "brim_ears" + || opt_key == "brim_ears_max_angle" || opt_key == "brim_connections_width") { steps.insert(psBrim); steps.insert(psSkirt); @@ -1084,6 +1086,7 @@ Print::_make_brim() const coord_t grow_distance = flow.scaled_width()/2; Polygons islands; + Points pt_ears; for (PrintObject* object : this->objects) { const Layer* layer0 = object->get_layer(0); @@ -1103,6 +1106,10 @@ Print::_make_brim() for (Polygon p : object_islands) { p.translate(copy); islands.push_back(p); + if(this->config.brim_ears) + for (const Point &p_corner : p.convex_points(this->config.brim_ears_max_angle.value * PI / 180.0)) { + pt_ears.push_back(p_corner); + } } } } @@ -1123,6 +1130,124 @@ Print::_make_brim() )); } + if(this->config.brim_ears){ + + //create ear pattern + coord_t size_ear = (scale_(this->config.brim_width.value) - flow.scaled_spacing()); + Polygon point_round; + point_round.points.push_back(Point(size_ear*1, 0*size_ear)); + point_round.points.push_back(Point(size_ear*0.966, 0.26*size_ear)); + point_round.points.push_back(Point(size_ear*0.87, 0.5*size_ear)); + point_round.points.push_back(Point(size_ear*0.7, 0.7*size_ear)); + point_round.points.push_back(Point(size_ear*0.5, 0.87*size_ear)); + point_round.points.push_back(Point(size_ear*0.26, 0.966*size_ear)); + point_round.points.push_back(Point(size_ear*0, 1*size_ear)); + point_round.points.push_back(Point(size_ear*-0.26, 0.966*size_ear)); + point_round.points.push_back(Point(size_ear*-0.5, 0.87*size_ear)); + point_round.points.push_back(Point(size_ear*-0.7, 0.7*size_ear)); + point_round.points.push_back(Point(size_ear*-0.87, 0.5*size_ear)); + point_round.points.push_back(Point(size_ear*-0.966, 0.26*size_ear)); + point_round.points.push_back(Point(size_ear*-1, 0*size_ear)); + point_round.points.push_back(Point(size_ear*-0.966, -0.26*size_ear)); + point_round.points.push_back(Point(size_ear*-0.87, -0.5*size_ear)); + point_round.points.push_back(Point(size_ear*-0.7, -0.7*size_ear)); + point_round.points.push_back(Point(size_ear*-0.5, -0.87*size_ear)); + point_round.points.push_back(Point(size_ear*-0.26, -0.966*size_ear)); + point_round.points.push_back(Point(size_ear*0, -1*size_ear)); + point_round.points.push_back(Point(size_ear*0.26, -0.966*size_ear)); + point_round.points.push_back(Point(size_ear*0.5, -0.87*size_ear)); + point_round.points.push_back(Point(size_ear*0.7, -0.7*size_ear)); + point_round.points.push_back(Point(size_ear*0.87, -0.5*size_ear)); + point_round.points.push_back(Point(size_ear*0.966, -0.26*size_ear)); + + //create ears + Polygons mouse_ears; + for (Point pt : pt_ears) { + mouse_ears.push_back(point_round); + mouse_ears.back().translate(pt); + } + + //intersection + Polylines lines = intersection_pl(union_pt_chained(loops), mouse_ears); + + //reorder them + Polylines lines_sorted; + Polyline* previous = NULL; + Polyline* best = NULL; + double best_dist = -1; + size_t best_idx = 0; + while (lines.size() > 0) { + if (previous == NULL) { + lines_sorted.push_back(lines.back()); + previous = &lines_sorted.back(); + lines.erase(lines.end() - 1); + } else { + best = NULL; + best_dist = -1; + best_idx = 0; + for (size_t i = 0; i < lines.size(); ++i) { + Polyline &viewed_line = lines[i]; + double dist = viewed_line.points.front().distance_to(previous->points.front()); + dist = std::min(dist, viewed_line.points.front().distance_to(previous->points.back())); + dist = std::min(dist, viewed_line.points.back().distance_to(previous->points.front())); + dist = std::min(dist, viewed_line.points.back().distance_to(previous->points.back())); + if (dist < best_dist || best == NULL) { + best = &viewed_line; + best_dist = dist; + best_idx = i; + } + } + if (best != NULL) { + //copy new line inside the sorted array. + lines_sorted.push_back(lines[best_idx]); + lines.erase(lines.begin() + best_idx); + + //connect if near enough + if (lines_sorted.size() > 1) { + size_t idx = lines_sorted.size() - 2; + bool connect = false; + if (lines_sorted[idx].points.back().distance_to(lines_sorted[idx + 1].points.front()) < flow.scaled_spacing() * 2) { + connect = true; + } else if (lines_sorted[idx].points.back().distance_to(lines_sorted[idx + 1].points.back()) < flow.scaled_spacing() * 2) { + lines_sorted[idx + 1].reverse(); + connect = true; + } else if (lines_sorted[idx].points.front().distance_to(lines_sorted[idx + 1].points.front()) < flow.scaled_spacing() * 2) { + lines_sorted[idx].reverse(); + connect = true; + } else if (lines_sorted[idx].points.front().distance_to(lines_sorted[idx + 1].points.back()) < flow.scaled_spacing() * 2) { + lines_sorted[idx].reverse(); + lines_sorted[idx + 1].reverse(); + connect = true; + } + + if (connect) { + //connect them + lines_sorted[idx].points.insert( + lines_sorted[idx].points.end(), + lines_sorted[idx + 1].points.begin(), + lines_sorted[idx + 1].points.end()); + lines_sorted.erase(lines_sorted.begin() + idx + 1); + idx--; + } + } + + //update last position + previous = &lines_sorted.back(); + } else { + previous == NULL; + } + + } + } + + //push into extrusions + for (Polyline &to_extrude : lines_sorted) { + ExtrusionPath path(erSkirt, mm3_per_mm, flow.width, flow.height); + path.polyline = to_extrude; + this->brim.append(path); + } + } + else { Polygons chained = union_pt_chained(loops); for (Polygons::const_reverse_iterator p = chained.rbegin(); p != chained.rend(); ++p) { diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index d0113b5029..27bafdd564 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -160,6 +160,23 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(0); + def = this->add("brim_ears", coBool); + def->label = __TRANS("Exterior brim ears"); + def->category = __TRANS("Skirt and brim"); + def->tooltip = __TRANS("Only draw the exterior brim over the sharp edges of the model."); + def->cli = "brim-ears!"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("brim_ears_max_angle", coFloat); + def->label = __TRANS("Brim ears max angle"); + def->category = __TRANS("Skirt and brim"); + def->tooltip = __TRANS("Maximum angle to let a brim ear appear."); + def->sidetext = "°"; + def->cli = "brim-ears-max-angle=f"; + def->min = 0; + def->max = 180; + def->default_value = new ConfigOptionFloat(125); + def = this->add("brim_width", coFloat); def->label = __TRANS("Exterior brim width"); def->category = __TRANS("Skirt and brim"); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 8176446934..7a989b8041 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -433,6 +433,8 @@ class PrintConfig : public GCodeConfig ConfigOptionFloat bridge_acceleration; ConfigOptionInt bridge_fan_speed; ConfigOptionFloat brim_connections_width; + ConfigOptionBool brim_ears; + ConfigOptionFloat brim_ears_max_angle; ConfigOptionFloat brim_width; ConfigOptionBool complete_objects; ConfigOptionBool cooling; @@ -495,6 +497,8 @@ class PrintConfig : public GCodeConfig OPT_PTR(bridge_acceleration); OPT_PTR(bridge_fan_speed); OPT_PTR(brim_connections_width); + OPT_PTR(brim_ears); + OPT_PTR(brim_ears_max_angle); OPT_PTR(brim_width); OPT_PTR(complete_objects); OPT_PTR(cooling); From 32b0adacd9a279ab717e54d335d0003798c41f2b Mon Sep 17 00:00:00 2001 From: supermerill Date: Thu, 10 Jan 2019 23:07:06 +0100 Subject: [PATCH 2/4] add some little tests to brim ears --- src/test/libslic3r/test_skirt_brim.cpp | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/test/libslic3r/test_skirt_brim.cpp b/src/test/libslic3r/test_skirt_brim.cpp index c526cecd05..c49b240dc5 100644 --- a/src/test/libslic3r/test_skirt_brim.cpp +++ b/src/test/libslic3r/test_skirt_brim.cpp @@ -153,6 +153,51 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { REQUIRE(tool == config->getInt("support_material_extruder") - 1); } } + WHEN("brim width to 1 with layer_width of 0.5") { + config->set("skirts", 0); + config->set("first_layer_extrusion_width", 0.5); + config->set("brim_width", 1); + config->set("brim_ears", false); + + THEN("2 brim lines") { + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + REQUIRE(print->brim.size() == 2); + } + } + + WHEN("brim ears on a square") { + config->set("skirts", 0); + config->set("first_layer_extrusion_width", 0.5); + config->set("brim_width", 1); + config->set("brim_ears", true); + config->set("brim_ears_max_angle", 91); + + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + + THEN("Four brim ears") { + REQUIRE(print->brim.size() == 4); + } + } + + + WHEN("brim ears on a square but with a too small max angle") { + config->set("skirts", 0); + config->set("first_layer_extrusion_width", 0.5); + config->set("brim_width", 1); + config->set("brim_ears", true); + config->set("brim_ears_max_angle", 89); + + THEN("no brim") { + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + REQUIRE(print->brim.size() == 0); + } + } WHEN("Object is plated with overhang support and a brim") { config->set("layer_height", 0.4); From cb9996a14ba6d2e664ea2bfa0ae41b74f9250f2a Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 10 Jan 2019 20:26:52 -0600 Subject: [PATCH 3/4] Wordsmithing brim_ears --- slic3r.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slic3r.pl b/slic3r.pl index 18d2225a60..f096994928 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -554,8 +554,8 @@ sub usage { of filament on the first layer, for each extruder (mm, 0+, default: $config->{min_skirt_length}) --brim-width Width of the brim that will get added to each object to help adhesion (mm, default: $config->{brim_width}) - --brim-ears set to true to print the brim only on sharp corners. - --brim-ears-max-angle Max angle for a corner to be assigned a brim ear. + --brim-ears Print brim only on sharp corners. + --brim-ears-max-angle Maximum angle considered for adding brim ears. (degrees, default: $config->{brim_ears_max_angle}) --interior-brim-width Width of the brim that will get printed inside object holes to help adhesion (mm, default: $config->{interior_brim_width}) From c15c4fdcf68466dd278af9aa9e5f8a7a7272d5ac Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 10 Jan 2019 20:28:41 -0600 Subject: [PATCH 4/4] Update PrintConfig.cpp --- xs/src/libslic3r/PrintConfig.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 27bafdd564..2901f8909d 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -163,14 +163,14 @@ PrintConfigDef::PrintConfigDef() def = this->add("brim_ears", coBool); def->label = __TRANS("Exterior brim ears"); def->category = __TRANS("Skirt and brim"); - def->tooltip = __TRANS("Only draw the exterior brim over the sharp edges of the model."); + def->tooltip = __TRANS("Draw the brim only over the sharp edges of the model."); def->cli = "brim-ears!"; def->default_value = new ConfigOptionBool(false); def = this->add("brim_ears_max_angle", coFloat); - def->label = __TRANS("Brim ears max angle"); + def->label = __TRANS("Brim ears Maximum Angle"); def->category = __TRANS("Skirt and brim"); - def->tooltip = __TRANS("Maximum angle to let a brim ear appear."); + def->tooltip = __TRANS("Maximum angle for a corner to place a brim ear."); def->sidetext = "°"; def->cli = "brim-ears-max-angle=f"; def->min = 0;