From e901514212f10cb5d18a296170af3a4c3cde5c03 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 18 Dec 2016 15:21:27 +0100 Subject: [PATCH] New feature: brim connections --- lib/Slic3r/GUI/3DScene.pm | 4 +- lib/Slic3r/GUI/Tab.pm | 5 ++- lib/Slic3r/Print.pm | 66 ++++++++++++++++++++++++++++++-- lib/Slic3r/Print/GCode.pm | 4 +- xs/src/libslic3r/Print.cpp | 5 ++- xs/src/libslic3r/PrintConfig.cpp | 8 ++++ xs/src/libslic3r/PrintConfig.hpp | 2 + 7 files changed, 84 insertions(+), 10 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 511305efc..c7b796146 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1285,7 +1285,9 @@ sub load_print_toolpaths { return if !$print->step_done(STEP_SKIRT); return if !$print->step_done(STEP_BRIM); - return if !$print->has_skirt && $print->config->brim_width == 0; + return if !$print->has_skirt + && $print->config->brim_width == 0 + && $print->config->brim_connections_width == 0; my $qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; my $tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 86c7cde9c..517d469f4 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -479,7 +479,7 @@ sub build { perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration default_acceleration skirts skirt_distance skirt_height min_skirt_length - brim_width + brim_connections_width brim_width support_material support_material_threshold support_material_enforce_layers raft_layers support_material_pattern support_material_spacing support_material_angle @@ -571,6 +571,7 @@ sub build { { my $optgroup = $page->new_optgroup('Brim'); $optgroup->append_single_option_line('brim_width'); + $optgroup->append_single_option_line('brim_connections_width'); } } @@ -848,7 +849,7 @@ sub _update { $self->get_field($_)->toggle($have_skirt) for qw(skirt_distance skirt_height); - my $have_brim = $config->brim_width > 0; + my $have_brim = $config->brim_width > 0 || $config->brim_connections_width; # perimeter_extruder uses the same logic as in Print::extruders() $self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index fbf15b47f..f3ad134e9 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -12,8 +12,9 @@ use Slic3r::ExtrusionPath ':roles'; use Slic3r::Flow ':roles'; use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX PI scale unscale convex_hull); use Slic3r::Geometry::Clipper qw(diff_ex union_ex intersection_ex intersection offset - offset2 union union_pt_chained JT_ROUND JT_SQUARE); + offset2 union union_pt_chained JT_ROUND JT_SQUARE diff_pl); use Slic3r::Print::State ':steps'; +use Slic3r::Surface qw(S_TYPE_BOTTOM); our $status_cb; @@ -356,7 +357,7 @@ sub make_brim { # checking whether we need to generate them $self->brim->clear; - if ($self->config->brim_width == 0) { + if ($self->config->brim_width == 0 && $self->config->brim_connections_width == 0) { $self->set_step_done(STEP_BRIM); return; } @@ -390,7 +391,7 @@ sub make_brim { } my @loops = (); - my $num_loops = sprintf "%.0f", $self->config->brim_width / $flow->width; + my $num_loops = int($self->config->brim_width / $flow->width + 0.5); for my $i (reverse 1 .. $num_loops) { # JT_SQUARE ensures no vertex is outside the given offset distance # -0.5 because islands are not represented by their centerlines @@ -409,6 +410,65 @@ sub make_brim { ), ), reverse @{union_pt_chained(\@loops)}); + if ($self->config->brim_connections_width > 0) { + # get islands to connects + @islands = map convex_hull(\@$_), @islands; + @islands = @{offset(\@islands, ($num_loops-0.2) * $flow->scaled_spacing, 10000, JT_SQUARE)}; + + # compute centroid for each island + my @centroids = map $_->centroid, @islands; + + # in order to check visibility we need to account for the connections width, + # so let's use grown islands + my $scaled_width = scale($self->config->brim_connections_width); + my $grown = offset(\@islands, +$scaled_width/2); + + # find pairs of islands having direct visibility + my @lines = (); + for my $i (0..$#islands) { + for my $j (($i+1)..$#islands) { + # check visibility + my $line = Slic3r::Line->new(@centroids[$i,$j]); + next if @{diff_pl([$line->as_polyline], $grown)} != 1; + + push @lines, $line; + } + } + + my $filler = Slic3r::Filler->new_from_type('rectilinear'); + $filler->set_spacing($flow->spacing); + $filler->set_dont_adjust(1); + + # subtract already generated connections in order to prevent crossings + # and overextrusion + my @other = (); + + foreach my $line (@lines) { + my $expolygons = diff_ex( + $line->grow($scaled_width/2), + [ @islands, @other ], + ); + push @other, map $_->clone, map @$_, @$expolygons; + + $filler->set_angle($line->direction); + foreach my $expolygon (@$expolygons) { + my $paths = $filler->fill_surface( + Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_BOTTOM), + layer_height => $first_layer_height, + density => 1, + ); + + $self->brim->append(map Slic3r::ExtrusionPath->new( + polyline => $_, + role => EXTR_ROLE_SKIRT, + mm3_per_mm => $mm3_per_mm, + width => $flow->width, + height => $first_layer_height, + ), @$paths); + } + } + } + $self->set_step_done(STEP_BRIM); } diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index 6764f5be8..25e8fb3c6 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -357,7 +357,7 @@ sub process_layer { # check whether we're going to apply spiralvase logic if (defined $self->_spiral_vase) { $self->_spiral_vase->enable( - ($layer->id > 0 || $self->print->config->brim_width == 0) + ($layer->id > 0 || $self->print->config->brim_width == 0 || $self->print->config->brim_connections_width == 0) && ($layer->id >= $self->print->config->skirt_height && !$self->print->has_infinite_skirt) && !defined(first { $_->region->config->bottom_solid_layers > $layer->id } @{$layer->regions}) && !defined(first { $_->perimeters->items_count > 1 } @{$layer->regions}) @@ -447,7 +447,7 @@ sub process_layer { $gcode .= $self->_gcodegen->set_extruder($self->print->regions->[0]->config->perimeter_extruder-1); $self->_gcodegen->set_origin(Slic3r::Pointf->new(0,0)); $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(1); - $gcode .= $self->_gcodegen->extrude_loop($_, 'brim', $object->config->support_material_speed) + $gcode .= $self->_gcodegen->extrude($_, 'brim', $object->config->support_material_speed) for @{$self->print->brim}; $self->_brim_done(1); $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(0); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 179d501b5..8b918eebb 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -163,7 +163,8 @@ Print::invalidate_state_by_config_options(const std::vector || *opt_key == "min_skirt_length" || *opt_key == "ooze_prevention") { steps.insert(psSkirt); - } else if (*opt_key == "brim_width") { + } else if (*opt_key == "brim_width" + || *opt_key == "brim_connections_width") { steps.insert(psBrim); steps.insert(psSkirt); } else if (*opt_key == "nozzle_diameter" @@ -304,7 +305,7 @@ Print::object_extruders() const FOREACH_REGION(this, region) { // these checks reflect the same logic used in the GUI for enabling/disabling // extruder selection fields - if ((*region)->config.perimeters.value > 0 || this->config.brim_width.value > 0) + if ((*region)->config.perimeters.value > 0 || this->config.brim_width.value > 0 || this->config.brim_connections_width.value > 0) extruders.insert((*region)->config.perimeter_extruder - 1); if ((*region)->config.fill_density.value > 0) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 7a4067d3e..9fa971121 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -91,6 +91,14 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(60); + def = this->add("brim_connections_width", coFloat); + def->label = "Brim connections width"; + def->tooltip = "If set to a positive value, straight connections will be built on the first layer between adjacent objects."; + def->sidetext = "mm"; + def->cli = "brim-connections-width=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0); + def = this->add("brim_width", coFloat); def->label = "Brim width"; def->tooltip = "Horizontal width of the brim that will be printed around each object on the first layer."; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index dff798a75..8388a0615 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -366,6 +366,7 @@ class PrintConfig : public GCodeConfig ConfigOptionInt bed_temperature; ConfigOptionFloat bridge_acceleration; ConfigOptionInt bridge_fan_speed; + ConfigOptionFloat brim_connections_width; ConfigOptionFloat brim_width; ConfigOptionBool complete_objects; ConfigOptionBool cooling; @@ -425,6 +426,7 @@ class PrintConfig : public GCodeConfig OPT_PTR(bed_temperature); OPT_PTR(bridge_acceleration); OPT_PTR(bridge_fan_speed); + OPT_PTR(brim_connections_width); OPT_PTR(brim_width); OPT_PTR(complete_objects); OPT_PTR(cooling);