diff --git a/README.md b/README.md index 2c71475d9..610bae473 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,8 @@ The author of the Silk icon set is Mark James. --support-material-enforce-layers Enforce support material on the specified number of layers from bottom, regardless of --support-material and threshold (0+, default: 0) + --dont-support-bridges + Experimental option for preventing support material from being generated under bridged areas (default: yes) Retraction options: --retract-length Length of retraction in mm when pausing extrusion (default: 1) diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 4834e9e3e..ba887907b 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -493,7 +493,8 @@ sub build { { title => 'Options for support material and raft', options => [qw(support_material_pattern support_material_spacing support_material_angle - support_material_interface_layers support_material_interface_spacing)], + support_material_interface_layers support_material_interface_spacing + dont_support_bridges)], }, ]); diff --git a/lib/Slic3r/Layer/BridgeDetector.pm b/lib/Slic3r/Layer/BridgeDetector.pm index 8620326c2..4aba4d1ff 100644 --- a/lib/Slic3r/Layer/BridgeDetector.pm +++ b/lib/Slic3r/Layer/BridgeDetector.pm @@ -3,7 +3,7 @@ use Moo; use List::Util qw(first sum max min); use Slic3r::Geometry qw(PI unscale scaled_epsilon rad2deg epsilon); -use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex union); +use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex union offset diff_pl union_ex); has 'expolygon' => (is => 'ro', required => 1); has 'lower_slices' => (is => 'rw', required => 1); # ExPolygons or ExPolygonCollection @@ -213,4 +213,41 @@ sub coverage { return $coverage; } +# this method returns the bridge edges (as polylines) that are not supported +# but would allow the entire bridge area to be bridged with detected angle +# if supported too +sub unsupported_edges { + my ($self, $angle) = @_; + + if (!defined $angle) { + return [] if !defined($angle = $self->angle); + } + + # get bridge edges (both contour and holes) + my @bridge_edges = map $_->split_at_first_point, @{$self->expolygon}; + $_->[0]->translate(1,0) for @bridge_edges; # workaround for Clipper bug, see comments in Slic3r::Polygon::clip_as_polyline() + + # get unsupported edges + my $grown_lower = offset([ map @$_, @{$self->lower_slices} ], +$self->extrusion_width); + my $unsupported = diff_pl( + \@bridge_edges, + $grown_lower, + ); + + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output( + "unsupported_" . rad2deg($angle) . ".svg", + expolygons => [$self->expolygon], + green_expolygons => $self->_anchors, + red_expolygons => union_ex($grown_lower), + no_arrows => 1, + polylines => [ map $_->split_at_first_point, @{$self->expolygon} ], + red_polylines => $unsupported, + ); + } + + return $unsupported; +} + 1; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index a150ac809..2decedaed 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -33,6 +33,9 @@ has 'fill_surfaces' => (is => 'rw', default => sub { Slic3r::Surface::Collection # collection of expolygons representing the bridged areas (thus not needing support material) has 'bridged' => (is => 'rw', default => sub { Slic3r::ExPolygon::Collection->new }); +# collection of polylines representing the unsupported bridge edges +has 'unsupported_bridge_edges' => (is => 'rw', default => sub { Slic3r::Polyline::Collection->new }); + # ordered collection of extrusion paths/loops to build all perimeters has 'perimeters' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); @@ -418,6 +421,7 @@ sub process_external_surfaces { if (defined $angle && $self->object->config->support_material) { $self->bridged->append(@{ $bridge_detector->coverage($angle) }); + $self->unsupported_bridge_edges->append(@{ $bridge_detector->unsupported_edges }); } } diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index db27d67fd..5df48b030 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -158,13 +158,34 @@ sub contact_area { # Void $diff means that there's no upper perimeter whose centerline is # outside the lower slice boundary, thus no overhang } - - # remove bridged areas - $diff = diff( - $diff, - [ map @$_, @{$layerm->bridged} ], - 1, - ); + + if ($self->object_config->dont_support_bridges) { + if (1) { + # remove the entire bridges and only support the unsupported edges + my @bridges = map $_->expolygon, + grep $_->bridge_angle != -1, + @{$layerm->fill_surfaces->filter_by_type(S_TYPE_BOTTOMBRIDGE)}; + + $diff = diff( + $diff, + [ map @$_, @bridges ], + 1, + ); + + push @$diff, @{intersection( + [ map @{$_->grow(+scale MARGIN)}, @{$layerm->unsupported_bridge_edges} ], + [ map @$_, @bridges ], + )} + + } else { + # just remove bridged areas + $diff = diff( + $diff, + [ map @$_, @{$layerm->bridged} ], + 1, + ); + } + } next if !@$diff; push @overhang, @$diff; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! diff --git a/slic3r.pl b/slic3r.pl index 205567f35..148092245 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -381,6 +381,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}) + --dont-support-bridges + Experimental option for preventing support material from being generated under bridged areas (default: yes) Retraction options: --retract-length Length of retraction in mm when pausing extrusion (default: $config->{retract_length}[0]) diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index 16885f213..b867ba586 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -139,6 +139,11 @@ class PrintConfigDef Options["disable_fan_first_layers"].cli = "disable-fan-first-layers=i"; Options["disable_fan_first_layers"].max = 1000; + Options["dont_support_bridges"].type = coBool; + Options["dont_support_bridges"].label = "Don't support bridges"; + Options["dont_support_bridges"].tooltip = "Experimental option for preventing support material from being generated under bridged areas."; + Options["dont_support_bridges"].cli = "dont-support-bridges!"; + Options["duplicate_distance"].type = coFloat; Options["duplicate_distance"].label = "Distance between copies"; Options["duplicate_distance"].tooltip = "Distance used for the auto-arrange feature of the plater."; @@ -968,6 +973,7 @@ class StaticPrintConfig : public virtual StaticConfig class PrintObjectConfig : public virtual StaticPrintConfig { public: + ConfigOptionBool dont_support_bridges; ConfigOptionFloatOrPercent extrusion_width; ConfigOptionFloatOrPercent first_layer_height; ConfigOptionBool infill_only_where_needed; @@ -988,6 +994,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig ConfigOptionInt support_material_threshold; PrintObjectConfig() : StaticPrintConfig() { + this->dont_support_bridges.value = true; this->extrusion_width.value = 0; this->extrusion_width.percent = false; this->first_layer_height.value = 0.35; @@ -1012,6 +1019,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig }; ConfigOption* option(const t_config_option_key opt_key, bool create = false) { + if (opt_key == "dont_support_bridges") return &this->dont_support_bridges; if (opt_key == "extrusion_width") return &this->extrusion_width; if (opt_key == "first_layer_height") return &this->first_layer_height; if (opt_key == "infill_only_where_needed") return &this->infill_only_where_needed;