diff --git a/README.md b/README.md index db1295993..f0aecf989 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,8 @@ The author of the Silk icon set is Mark James. --bed-size Bed size, only used for auto-arrange (mm, default: 200,200) --duplicate-grid Number of items with grid arrangement (default: 1,1) --duplicate-distance Distance in mm between copies (default: 6) + --xy-size-compensation + Grow/shrink objects by the configured absolute distance (mm, default: 0) Sequential printing options: --complete-objects When printing multiple objects and/or copies, complete each one before diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 15c1321fd..fc7545941 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -552,7 +552,7 @@ sub build { }, { title => 'Other', - options => [($Slic3r::have_threads ? qw(threads) : ()), qw(resolution)], + options => [($Slic3r::have_threads ? qw(threads) : ()), qw(resolution xy_size_compensation)], }, ]); } diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 7918871d4..4f139f7d0 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -251,6 +251,59 @@ sub slice { pop @{$self->layers} while @{$self->layers} && (!map @{$_->slices}, @{$self->layers->[-1]->regions}); foreach my $layer (@{ $self->layers }) { + # apply size compensation + if ($self->config->xy_size_compensation != 0) { + my $delta = scale($self->config->xy_size_compensation); + if (@{$layer->regions} == 1) { + # single region + my $layerm = $layer->regions->[0]; + my $slices = [ map $_->p, @{$layerm->slices} ]; + $layerm->slices->clear; + $layerm->slices->append(Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNAL, + )) for @{offset_ex($slices, $delta)}; + } else { + if ($delta < 0) { + # multiple regions, shrinking + # we apply the offset to the combined shape, then intersect it + # with the original slices for each region + my $slices = union([ map $_->p, map @{$_->slices}, @{$layer->regions} ]); + $slices = offset($slices, $delta); + foreach my $layerm (@{$layer->regions}) { + my $this_slices = intersection_ex( + $slices, + [ map $_->p, @{$layerm->slices} ], + ); + $layerm->slices->clear; + $layerm->slices->append(Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNAL, + )) for @$this_slices; + } + } else { + # multiple regions, growing + # this is an ambiguous case, since it's not clear how to grow regions where they are going to overlap + # so we give priority to the first one and so on + for my $i (0..$#{$layer->regions}) { + my $layerm = $layer->regions->[$i]; + my $slices = offset_ex([ map $_->p, @{$layerm->slices} ], $delta); + if ($i > 0) { + $slices = diff_ex( + [ map @$_, @$slices ], + [ map $_->p, map @{$_->slices}, map $layer->regions->[$_], 0..($i-1) ], # slices of already processed regions + ); + } + $layerm->slices->clear; + $layerm->slices->append(Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNAL, + )) for @$slices; + } + } + } + } + # merge all regions' slices to get islands $layer->make_slices; } diff --git a/slic3r.pl b/slic3r.pl index 578c6a4ae..0baef80ec 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -436,6 +436,8 @@ $j --bed-size Bed size, only used for auto-arrange (mm, default: $config->{bed_size}->[0],$config->{bed_size}->[1]) --duplicate-grid Number of items with grid arrangement (default: 1,1) --duplicate-distance Distance in mm between copies (default: $config->{duplicate_distance}) + --xy-size-compensation + Grow/shrink objects by the configured absolute distance (mm, default: $config->{xy_size_compensation}) Sequential printing options: --complete-objects When printing multiple objects and/or copies, complete each one before diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index 3f43ebfce..72c083e48 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -962,6 +962,13 @@ class PrintConfigDef Options["wipe"].tooltip = "This flag will move the nozzle while retracting to minimize the possible blob on leaky extruders."; Options["wipe"].cli = "wipe!"; + Options["xy_size_compensation"].type = coFloat; + Options["xy_size_compensation"].label = "XY Size Compensation"; + Options["xy_size_compensation"].category = "Advanced"; + Options["xy_size_compensation"].tooltip = "The object will be grown/shrunk in the XY plane by the configured value (negative = inwards, positive = outwards). This might be useful for fine-tuning hole sizes."; + Options["xy_size_compensation"].sidetext = "mm"; + Options["xy_size_compensation"].cli = "xy-size-compensation=f"; + Options["z_offset"].type = coFloat; Options["z_offset"].label = "Z offset"; Options["z_offset"].tooltip = "This value will be added (or subtracted) from all the Z coordinates in the output G-code. It is used to compensate for bad Z endstop position: for example, if your endstop zero actually leaves the nozzle 0.3mm far from the print bed, set this to -0.3 (or fix your endstop)."; @@ -1034,6 +1041,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig ConfigOptionFloat support_material_spacing; ConfigOptionFloat support_material_speed; ConfigOptionInt support_material_threshold; + ConfigOptionFloat xy_size_compensation; PrintObjectConfig() : StaticPrintConfig() { this->dont_support_bridges.value = true; @@ -1061,6 +1069,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig this->support_material_spacing.value = 2.5; this->support_material_speed.value = 60; this->support_material_threshold.value = 0; + this->xy_size_compensation.value = 0; }; ConfigOption* option(const t_config_option_key opt_key, bool create = false) { @@ -1085,6 +1094,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig if (opt_key == "support_material_spacing") return &this->support_material_spacing; if (opt_key == "support_material_speed") return &this->support_material_speed; if (opt_key == "support_material_threshold") return &this->support_material_threshold; + if (opt_key == "xy_size_compensation") return &this->xy_size_compensation; return NULL; };