Browse Source

A new feature "support_material_buildplate_only" implemented.
Also a bug has been fixed for zero interface layers. Before
slic3r would put infinite number of interface layers over top surfaces,
if the number of interface layers was set to zero.

bubnikv 8 years ago
parent
commit
5bb37ad2c4

+ 2 - 1
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');
     }

+ 2 - 1
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');
         }
     }

+ 52 - 10
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);
         }

+ 2 - 0
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)
   

+ 7 - 0
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";

+ 2 - 0
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);

+ 1 - 0
xs/src/libslic3r/PrintObject.cpp

@@ -236,6 +236,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
             || *opt_key == "support_material_interface_extruder"
             || *opt_key == "support_material_interface_spacing"
             || *opt_key == "support_material_interface_speed"
+            || *opt_key == "support_material_buildplate_only"
             || *opt_key == "support_material_pattern"
             || *opt_key == "support_material_spacing"
             || *opt_key == "support_material_threshold"