diff --git a/lib/Slic3r/GUI/SimpleTab.pm b/lib/Slic3r/GUI/SimpleTab.pm index 13c6efc88..333e7ab1b 100644 --- a/lib/Slic3r/GUI/SimpleTab.pm +++ b/lib/Slic3r/GUI/SimpleTab.pm @@ -124,7 +124,7 @@ sub build { layer_height perimeters top_solid_layers bottom_solid_layers fill_density fill_pattern external_fill_pattern support_material support_material_spacing raft_layers - support_material_contact_distance dont_support_bridges + support_material_contact_distance support_material_buildplate_only dont_support_bridges perimeter_speed infill_speed travel_speed brim_width xy_size_compensation @@ -155,6 +155,7 @@ sub build { $optgroup->append_single_option_line('support_material'); $optgroup->append_single_option_line('support_material_spacing'); $optgroup->append_single_option_line('support_material_contact_distance'); + $optgroup->append_single_option_line('support_material_buildplate_only'); $optgroup->append_single_option_line('dont_support_bridges'); $optgroup->append_single_option_line('raft_layers'); } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index d1ea0e432..7304c2f58 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -482,7 +482,7 @@ sub build { raft_layers support_material_pattern support_material_spacing support_material_angle support_material_interface_layers support_material_interface_spacing - support_material_contact_distance dont_support_bridges + support_material_contact_distance support_material_buildplate_only dont_support_bridges notes complete_objects extruder_clearance_radius extruder_clearance_height gcode_comments output_filename_format @@ -592,6 +592,7 @@ sub build { $optgroup->append_single_option_line('support_material_angle'); $optgroup->append_single_option_line('support_material_interface_layers'); $optgroup->append_single_option_line('support_material_interface_spacing'); + $optgroup->append_single_option_line('support_material_buildplate_only'); $optgroup->append_single_option_line('dont_support_bridges'); } } diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index eea6397af..b1e82f088 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -1,3 +1,5 @@ +# Instantiated by Slic3r::Print::Object->_support_material() +# only generate() and contact_distance() are called from the outside of this module. package Slic3r::Print::SupportMaterial; use Moo; @@ -25,6 +27,7 @@ use constant PILLAR_SIZE => 2.5; use constant PILLAR_SPACING => 10; sub generate { + # $object is Slic3r::Print::Object my ($self, $object) = @_; # Determine the top surfaces of the support, defined as: @@ -38,7 +41,7 @@ sub generate { # the layer heights of support material and to clip support to the object # silhouette. my ($top) = $self->object_top($object, $contact); - + # We now know the upper and lower boundaries for our support material object # (@$contact_z and @$top_z), so we can generate intermediate layers. my $support_z = $self->support_layers_z( @@ -88,6 +91,7 @@ sub generate { } sub contact_area { + # $object is Slic3r::Print::Object my ($self, $object) = @_; # if user specified a custom angle threshold, convert it to radians @@ -97,6 +101,12 @@ sub contact_area { Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); } + # Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces + # and subtract $buildplate_only_top_surfaces from the contact surfaces, so + # there is no contact surface supported by a top surface. + my $buildplate_only = $self->object_config->support_material && $self->object_config->support_material_buildplate_only; + my $buildplate_only_top_surfaces = []; + # determine contact areas my %contact = (); # contact_z => [ polygons ] my %overhang = (); # contact_z => [ polygons ] - this stores the actual overhang supported by each contact layer @@ -113,7 +123,22 @@ sub contact_area { last if $layer_id > 0; } my $layer = $object->get_layer($layer_id); - + + if ($buildplate_only) { + # Collect the top surfaces up to this layer and merge them. + my $projection_new = []; + push @$projection_new, ( map $_->p, map @{$_->slices->filter_by_type(S_TYPE_TOP)}, @{$layer->regions} ); + if (@$projection_new) { + # Merge the new top surfaces with the preceding top surfaces. + # Apply the safety offset to the newly added polygons, so they will connect + # with the polygons collected before, + # but don't apply the safety offset during the union operation as it would + # inflate the polygons over and over. + push @$buildplate_only_top_surfaces, @{ offset($projection_new, scale(0.01)) }; + $buildplate_only_top_surfaces = union($buildplate_only_top_surfaces, 0); + } + } + # detect overhangs and contact areas needed to support them my (@overhang, @contact) = (); if ($layer_id == 0) { @@ -239,8 +264,14 @@ sub contact_area { 1, ); } + } # if ($self->object_config->dont_support_bridges) + + if ($buildplate_only) { + # Don't support overhangs above the top surfaces. + # This step is done before the contact surface is calcuated by growing the overhang region. + $diff = diff($diff, $buildplate_only_top_surfaces); } - + next if !@$diff; push @overhang, @$diff; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! @@ -249,11 +280,16 @@ sub contact_area { # We increment the area in steps because we don't want our support to overflow # on the other side of the object (if it's very thin). { - my @slices_margin = @{offset([ map @$_, @{$lower_layer->slices} ], +$fw/2)}; + my $slices_margin = offset([ map @$_, @{$lower_layer->slices} ], +$fw/2); + if ($buildplate_only) { + # Trim the inflated contact surfaces by the top surfaces as well. + push @$slices_margin, map $_->clone, @{$buildplate_only_top_surfaces}; + $slices_margin = union($slices_margin); + } for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) { $diff = diff( offset($diff, $_), - \@slices_margin, + $slices_margin, ); } } @@ -280,14 +316,15 @@ sub contact_area { if (0) { require "Slic3r/SVG.pm"; - Slic3r::SVG::output("contact_" . $contact_z . ".svg", - expolygons => union_ex(\@contact), - red_expolygons => union_ex(\@overhang), + Slic3r::SVG::output("out\\contact_" . $contact_z . ".svg", + green_expolygons => union_ex($buildplate_only_top_surfaces), + blue_expolygons => union_ex(\@contact), + red_expolygons => union_ex(\@overhang), ); } } } - + return (\%contact, \%overhang); } @@ -297,6 +334,8 @@ sub object_top { # find object top surfaces # we'll use them to clip our support and detect where does it stick my %top = (); # print_z => [ expolygons ] + return \%top if ($self->object_config->support_material_buildplate_only); + my $projection = []; foreach my $layer (reverse @{$object->layers}) { if (my @top = map @{$_->slices->filter_by_type(S_TYPE_TOP)}, @{$layer->regions}) { @@ -429,6 +468,9 @@ sub generate_interface_layers { sub generate_bottom_interface_layers { my ($self, $support_z, $base, $top, $interface) = @_; + + # If no interface layers are allowed, don't generate bottom interface layers. + return if $self->object_config->support_material_interface_layers == 0; my $area_threshold = $self->interface_flow->scaled_spacing ** 2; @@ -717,7 +759,7 @@ sub generate_toolpaths { width => $_interface_flow->width, height => $layer->height, ), @p; - } + } $layer->support_interface_fills->append(@paths); } diff --git a/slic3r.pl b/slic3r.pl index 466263f66..573d01068 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -432,6 +432,8 @@ $j --support-material-enforce-layers Enforce support material on the specified number of layers from bottom, regardless of --support-material and threshold (0+, default: $config->{support_material_enforce_layers}) + --support-material-buildplate-only + Only create support if it lies on a build plate. Don't create support on a print. (default: no) --dont-support-bridges Experimental option for preventing support material from being generated under bridged areas (default: yes) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 5c0aec65d..be5226fe3 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1092,6 +1092,13 @@ PrintConfigDef::PrintConfigDef() def->max = 359; def->default_value = new ConfigOptionInt(0); + def = this->add("support_material_buildplate_only", coBool); + def->label = "Support on build plate only"; + def->category = "Support material"; + def->tooltip = "Only create support if it lies on a build plate. Don't create support on a print."; + def->cli = "support-material-buildplate-only!"; + def->default_value = new ConfigOptionBool(false); + def = this->add("support_material_contact_distance", coFloat); def->gui_type = "f_enum_open"; def->label = "Contact Z distance"; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index eebd5d81d..c459bf1c1 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -145,6 +145,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig // ConfigOptionFloat seam_preferred_direction_jitter; ConfigOptionBool support_material; ConfigOptionInt support_material_angle; + ConfigOptionBool support_material_buildplate_only; ConfigOptionFloat support_material_contact_distance; ConfigOptionInt support_material_enforce_layers; ConfigOptionInt support_material_extruder; @@ -177,6 +178,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig // OPT_PTR(seam_preferred_direction_jitter); OPT_PTR(support_material); OPT_PTR(support_material_angle); + OPT_PTR(support_material_buildplate_only); OPT_PTR(support_material_contact_distance); OPT_PTR(support_material_enforce_layers); OPT_PTR(support_material_extruder); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 4f9c04d03..8b2b34ae0 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -236,6 +236,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector