Merge branch 'master' into grow-narrow
Conflicts: lib/Slic3r/Fill.pm lib/Slic3r/Print/Object.pm
This commit is contained in:
commit
1064c9bb2a
@ -197,6 +197,7 @@ The author of the Silk icon set is Mark James.
|
|||||||
--extra-perimeters Add more perimeters when needed (default: yes)
|
--extra-perimeters Add more perimeters when needed (default: yes)
|
||||||
--randomize-start Randomize starting point across layers (default: yes)
|
--randomize-start Randomize starting point across layers (default: yes)
|
||||||
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
||||||
|
--external-perimeters-first Reverse perimeter order. (default: no)
|
||||||
--only-retract-when-crossing-perimeters
|
--only-retract-when-crossing-perimeters
|
||||||
Disable retraction when travelling between infill paths inside the same island.
|
Disable retraction when travelling between infill paths inside the same island.
|
||||||
(default: yes)
|
(default: yes)
|
||||||
@ -288,6 +289,7 @@ The author of the Silk icon set is Mark James.
|
|||||||
|
|
||||||
Miscellaneous options:
|
Miscellaneous options:
|
||||||
--notes Notes to be added as comments to the output file
|
--notes Notes to be added as comments to the output file
|
||||||
|
--resolution Minimum detail resolution (mm, set zero for full resolution, default: 0)
|
||||||
|
|
||||||
Flow options (advanced):
|
Flow options (advanced):
|
||||||
--extrusion-width Set extrusion width manually; it accepts either an absolute value in mm
|
--extrusion-width Set extrusion width manually; it accepts either an absolute value in mm
|
||||||
@ -298,6 +300,8 @@ The author of the Silk icon set is Mark James.
|
|||||||
Set a different extrusion width for perimeters
|
Set a different extrusion width for perimeters
|
||||||
--infill-extrusion-width
|
--infill-extrusion-width
|
||||||
Set a different extrusion width for infill
|
Set a different extrusion width for infill
|
||||||
|
--solid-infill-extrusion-width
|
||||||
|
Set a different extrusion width for solid infill
|
||||||
--top-infill-extrusion-width
|
--top-infill-extrusion-width
|
||||||
Set a different extrusion width for top infill
|
Set a different extrusion width for top infill
|
||||||
--support-material-extrusion-width
|
--support-material-extrusion-width
|
||||||
|
@ -67,7 +67,7 @@ use constant SCALED_RESOLUTION => RESOLUTION / SCALING_FACTOR;
|
|||||||
use constant OVERLAP_FACTOR => 1;
|
use constant OVERLAP_FACTOR => 1;
|
||||||
use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI;
|
use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI;
|
||||||
use constant LOOP_CLIPPING_LENGTH_OVER_SPACING => 0.15;
|
use constant LOOP_CLIPPING_LENGTH_OVER_SPACING => 0.15;
|
||||||
use constant PERIMETER_INFILL_OVERLAP_OVER_SPACING => 0.45;
|
use constant INFILL_OVERLAP_OVER_SPACING => 0.45;
|
||||||
|
|
||||||
our $Config;
|
our $Config;
|
||||||
|
|
||||||
|
@ -37,6 +37,15 @@ our $Options = {
|
|||||||
default => $Slic3r::have_threads ? 2 : 1,
|
default => $Slic3r::have_threads ? 2 : 1,
|
||||||
readonly => !$Slic3r::have_threads,
|
readonly => !$Slic3r::have_threads,
|
||||||
},
|
},
|
||||||
|
'resolution' => {
|
||||||
|
label => 'Resolution',
|
||||||
|
tooltip => 'Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.',
|
||||||
|
sidetext => 'mm',
|
||||||
|
cli => 'resolution=f',
|
||||||
|
type => 'f',
|
||||||
|
min => 0,
|
||||||
|
default => 0,
|
||||||
|
},
|
||||||
|
|
||||||
# output options
|
# output options
|
||||||
'output_filename_format' => {
|
'output_filename_format' => {
|
||||||
@ -368,7 +377,7 @@ our $Options = {
|
|||||||
cli => 'first-layer-height=s',
|
cli => 'first-layer-height=s',
|
||||||
type => 'f',
|
type => 'f',
|
||||||
ratio_over => 'layer_height',
|
ratio_over => 'layer_height',
|
||||||
default => '100%',
|
default => 0.35,
|
||||||
},
|
},
|
||||||
'infill_every_layers' => {
|
'infill_every_layers' => {
|
||||||
label => 'Infill every',
|
label => 'Infill every',
|
||||||
@ -437,8 +446,16 @@ our $Options = {
|
|||||||
type => 'f',
|
type => 'f',
|
||||||
default => 0,
|
default => 0,
|
||||||
},
|
},
|
||||||
|
'solid_infill_extrusion_width' => {
|
||||||
|
label => 'Solid infill',
|
||||||
|
tooltip => 'Set this to a non-zero value to set a manual extrusion width for infill for solid surfaces. If expressed as percentage (for example 90%) if will be computed over layer height.',
|
||||||
|
sidetext => 'mm or % (leave 0 for default)',
|
||||||
|
cli => 'solid-infill-extrusion-width=s',
|
||||||
|
type => 'f',
|
||||||
|
default => 0,
|
||||||
|
},
|
||||||
'top_infill_extrusion_width' => {
|
'top_infill_extrusion_width' => {
|
||||||
label => 'Top infill',
|
label => 'Top solid infill',
|
||||||
tooltip => 'Set this to a non-zero value to set a manual extrusion width for infill for top surfaces. You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. If expressed as percentage (for example 90%) if will be computed over layer height.',
|
tooltip => 'Set this to a non-zero value to set a manual extrusion width for infill for top surfaces. You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. If expressed as percentage (for example 90%) if will be computed over layer height.',
|
||||||
sidetext => 'mm or % (leave 0 for default)',
|
sidetext => 'mm or % (leave 0 for default)',
|
||||||
cli => 'top-infill-extrusion-width=s',
|
cli => 'top-infill-extrusion-width=s',
|
||||||
@ -506,7 +523,7 @@ our $Options = {
|
|||||||
type => 'select',
|
type => 'select',
|
||||||
values => [qw(rectilinear line concentric honeycomb hilbertcurve archimedeanchords octagramspiral)],
|
values => [qw(rectilinear line concentric honeycomb hilbertcurve archimedeanchords octagramspiral)],
|
||||||
labels => [qw(rectilinear line concentric honeycomb), 'hilbertcurve (slow)', 'archimedeanchords (slow)', 'octagramspiral (slow)'],
|
labels => [qw(rectilinear line concentric honeycomb), 'hilbertcurve (slow)', 'archimedeanchords (slow)', 'octagramspiral (slow)'],
|
||||||
default => 'rectilinear',
|
default => 'honeycomb',
|
||||||
},
|
},
|
||||||
'solid_fill_pattern' => {
|
'solid_fill_pattern' => {
|
||||||
label => 'Top/bottom fill pattern',
|
label => 'Top/bottom fill pattern',
|
||||||
@ -562,6 +579,13 @@ our $Options = {
|
|||||||
type => 'bool',
|
type => 'bool',
|
||||||
default => 0,
|
default => 0,
|
||||||
},
|
},
|
||||||
|
'external_perimeters_first' => {
|
||||||
|
label => 'External perimeters first',
|
||||||
|
tooltip => 'Print contour perimeters from the outermost one to the innermost one instead of the default inverse order.',
|
||||||
|
cli => 'external-perimeters-first!',
|
||||||
|
type => 'bool',
|
||||||
|
default => 0,
|
||||||
|
},
|
||||||
'only_retract_when_crossing_perimeters' => {
|
'only_retract_when_crossing_perimeters' => {
|
||||||
label => 'Only retract when crossing perimeters',
|
label => 'Only retract when crossing perimeters',
|
||||||
tooltip => 'Disables retraction when travelling between infill paths inside the same island.',
|
tooltip => 'Disables retraction when travelling between infill paths inside the same island.',
|
||||||
|
@ -172,8 +172,13 @@ sub clip_line {
|
|||||||
|
|
||||||
sub simplify {
|
sub simplify {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$_->simplify(@_) for @$self;
|
my ($tolerance) = @_;
|
||||||
$self;
|
|
||||||
|
# it would be nice to have a multilinestring_simplify method in B::G::U
|
||||||
|
my @simplified = Slic3r::Geometry::Clipper::simplify_polygons(
|
||||||
|
[ map Boost::Geometry::Utils::linestring_simplify($_, $tolerance), @$self ],
|
||||||
|
);
|
||||||
|
return @{ Slic3r::Geometry::Clipper::union_ex([ @simplified ]) };
|
||||||
}
|
}
|
||||||
|
|
||||||
sub scale {
|
sub scale {
|
||||||
|
@ -5,8 +5,8 @@ require Exporter;
|
|||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER
|
our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER
|
||||||
EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER
|
EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER
|
||||||
EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_BRIDGE EXTR_ROLE_SKIRT
|
EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_BRIDGE
|
||||||
EXTR_ROLE_SUPPORTMATERIAL EXTR_ROLE_GAPFILL);
|
EXTR_ROLE_INTERNALBRIDGE EXTR_ROLE_SKIRT EXTR_ROLE_SUPPORTMATERIAL EXTR_ROLE_GAPFILL);
|
||||||
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
|
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
|
||||||
|
|
||||||
use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points);
|
use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points);
|
||||||
@ -30,9 +30,10 @@ use constant EXTR_ROLE_FILL => 4;
|
|||||||
use constant EXTR_ROLE_SOLIDFILL => 5;
|
use constant EXTR_ROLE_SOLIDFILL => 5;
|
||||||
use constant EXTR_ROLE_TOPSOLIDFILL => 6;
|
use constant EXTR_ROLE_TOPSOLIDFILL => 6;
|
||||||
use constant EXTR_ROLE_BRIDGE => 7;
|
use constant EXTR_ROLE_BRIDGE => 7;
|
||||||
use constant EXTR_ROLE_SKIRT => 8;
|
use constant EXTR_ROLE_INTERNALBRIDGE => 8;
|
||||||
use constant EXTR_ROLE_SUPPORTMATERIAL => 9;
|
use constant EXTR_ROLE_SKIRT => 9;
|
||||||
use constant EXTR_ROLE_GAPFILL => 10;
|
use constant EXTR_ROLE_SUPPORTMATERIAL => 10;
|
||||||
|
use constant EXTR_ROLE_GAPFILL => 11;
|
||||||
|
|
||||||
use constant PACK_FMT => 'ffca*';
|
use constant PACK_FMT => 'ffca*';
|
||||||
|
|
||||||
@ -81,6 +82,11 @@ sub clip_with_expolygon {
|
|||||||
return @paths;
|
return @paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub simplify {
|
||||||
|
my $self = shift;
|
||||||
|
$self->polyline($self->polyline->simplify(@_));
|
||||||
|
}
|
||||||
|
|
||||||
sub points {
|
sub points {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return $self->polyline;
|
return $self->polyline;
|
||||||
|
@ -93,7 +93,8 @@ sub make_fill {
|
|||||||
expolygon => $_,
|
expolygon => $_,
|
||||||
surface_type => $group->[0]->surface_type,
|
surface_type => $group->[0]->surface_type,
|
||||||
bridge_angle => $group->[0]->bridge_angle,
|
bridge_angle => $group->[0]->bridge_angle,
|
||||||
depth_layers => $group->[0]->depth_layers,
|
thickness => $group->[0]->thickness,
|
||||||
|
thickness_layers => $group->[0]->thickness_layers,
|
||||||
), @$union;
|
), @$union;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +108,7 @@ sub make_fill {
|
|||||||
# we are going to grow such regions by overlapping them with the void (if any)
|
# we are going to grow such regions by overlapping them with the void (if any)
|
||||||
# TODO: detect and investigate whether there could be narrow regions without
|
# TODO: detect and investigate whether there could be narrow regions without
|
||||||
# any void neighbors
|
# any void neighbors
|
||||||
my $distance_between_surfaces = $layerm->infill_flow->scaled_spacing;
|
my $distance_between_surfaces = $layerm->solid_infill_flow->scaled_spacing;
|
||||||
{
|
{
|
||||||
my $collapsed = diff(
|
my $collapsed = diff(
|
||||||
[ map @{$_->expolygon}, @surfaces ],
|
[ map @{$_->expolygon}, @surfaces ],
|
||||||
@ -132,7 +133,7 @@ sub make_fill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# add spacing between surfaces
|
# add spacing between surfaces
|
||||||
@surfaces = map $_->offset(-$distance_between_surfaces/2), @surfaces;
|
@surfaces = map $_->offset(-$distance_between_surfaces / 2 * &Slic3r::INFILL_OVERLAP_OVER_SPACING), @surfaces;
|
||||||
|
|
||||||
my @fills = ();
|
my @fills = ();
|
||||||
my @fills_ordering_points = ();
|
my @fills_ordering_points = ();
|
||||||
@ -140,9 +141,12 @@ sub make_fill {
|
|||||||
next if $surface->surface_type == S_TYPE_INTERNALVOID;
|
next if $surface->surface_type == S_TYPE_INTERNALVOID;
|
||||||
my $filler = $Slic3r::Config->fill_pattern;
|
my $filler = $Slic3r::Config->fill_pattern;
|
||||||
my $density = $Slic3r::Config->fill_density;
|
my $density = $Slic3r::Config->fill_density;
|
||||||
my $flow_spacing = ($surface->surface_type == S_TYPE_TOP)
|
my $flow = ($surface->surface_type == S_TYPE_TOP)
|
||||||
? $layerm->top_infill_flow->spacing
|
? $layerm->top_infill_flow
|
||||||
: $layerm->infill_flow->spacing;
|
: $surface->is_solid
|
||||||
|
? $layerm->solid_infill_flow
|
||||||
|
: $layerm->infill_flow;
|
||||||
|
my $flow_spacing = $flow->spacing;
|
||||||
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
|
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
|
||||||
my $is_solid = $surface->is_solid;
|
my $is_solid = $surface->is_solid;
|
||||||
|
|
||||||
@ -184,12 +188,14 @@ sub make_fill {
|
|||||||
paths => [
|
paths => [
|
||||||
map Slic3r::ExtrusionPath->pack(
|
map Slic3r::ExtrusionPath->pack(
|
||||||
polyline => Slic3r::Polyline->new(@$_),
|
polyline => Slic3r::Polyline->new(@$_),
|
||||||
role => ($is_bridge
|
role => ($surface->surface_type == S_TYPE_INTERNALBRIDGE
|
||||||
|
? EXTR_ROLE_INTERNALBRIDGE
|
||||||
|
: $is_bridge
|
||||||
? EXTR_ROLE_BRIDGE
|
? EXTR_ROLE_BRIDGE
|
||||||
: $is_solid
|
: $is_solid
|
||||||
? ($surface->surface_type == S_TYPE_TOP ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
|
? ($surface->surface_type == S_TYPE_TOP ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
|
||||||
: EXTR_ROLE_FILL),
|
: EXTR_ROLE_FILL),
|
||||||
height => $surface->depth_layers * $layerm->height,
|
height => $surface->thickness,
|
||||||
flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
|
flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
|
||||||
), @paths,
|
), @paths,
|
||||||
],
|
],
|
||||||
|
@ -20,7 +20,7 @@ sub infill_direction {
|
|||||||
|
|
||||||
if (defined $self->layer_id) {
|
if (defined $self->layer_id) {
|
||||||
# alternate fill direction
|
# alternate fill direction
|
||||||
my $layer_num = $self->layer_id / $surface->depth_layers;
|
my $layer_num = $self->layer_id / $surface->thickness_layers;
|
||||||
my $angle = $self->angles->[$layer_num % @{$self->angles}];
|
my $angle = $self->angles->[$layer_num % @{$self->angles}];
|
||||||
$rotate[0] = Slic3r::Geometry::deg2rad($self->angle) + $angle if $angle;
|
$rotate[0] = Slic3r::Geometry::deg2rad($self->angle) + $angle if $angle;
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,10 @@ sub fill_surface {
|
|||||||
# infill math
|
# infill math
|
||||||
my $min_spacing = scale $params{flow_spacing};
|
my $min_spacing = scale $params{flow_spacing};
|
||||||
my $distance = $min_spacing / $params{density};
|
my $distance = $min_spacing / $params{density};
|
||||||
my $overlap_distance = scale $params{flow_spacing} * &Slic3r::PERIMETER_INFILL_OVERLAP_OVER_SPACING;
|
|
||||||
|
|
||||||
my $cache_id = sprintf "d%s_s%s_a%s",
|
my $cache_id = sprintf "d%s_s%s_a%s",
|
||||||
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
||||||
if (!$self->cache->{$cache_id}) {
|
if (!$self->cache->{$cache_id} || !defined $self->bounding_box) {
|
||||||
|
|
||||||
# hexagons math
|
# hexagons math
|
||||||
my $hex_side = $distance / (sqrt(3)/2);
|
my $hex_side = $distance / (sqrt(3)/2);
|
||||||
@ -40,15 +39,10 @@ sub fill_surface {
|
|||||||
|
|
||||||
# adjust actual bounding box to the nearest multiple of our hex pattern
|
# adjust actual bounding box to the nearest multiple of our hex pattern
|
||||||
# and align it so that it matches across layers
|
# and align it so that it matches across layers
|
||||||
$self->bounding_box([ $expolygon->bounding_box ]) if !defined $self->bounding_box;
|
my $bounding_box = [ $self->bounding_box ? @{$self->bounding_box} : $expolygon->bounding_box ];
|
||||||
my $bounding_box = [ 0, 0, $self->bounding_box->[X2], $self->bounding_box->[Y2] ];
|
$bounding_box->[$_] = 0 for X1, Y1;
|
||||||
{
|
{
|
||||||
my $bb_polygon = Slic3r::Polygon->new([
|
my $bb_polygon = Slic3r::Polygon->new_from_bounding_box($bounding_box);
|
||||||
[ $bounding_box->[X1], $bounding_box->[Y1] ],
|
|
||||||
[ $bounding_box->[X2], $bounding_box->[Y1] ],
|
|
||||||
[ $bounding_box->[X2], $bounding_box->[Y2] ],
|
|
||||||
[ $bounding_box->[X1], $bounding_box->[Y2] ],
|
|
||||||
]);
|
|
||||||
$bb_polygon->rotate($rotate_vector->[0][0], $hex_center);
|
$bb_polygon->rotate($rotate_vector->[0][0], $hex_center);
|
||||||
$bounding_box = [ Slic3r::Geometry::bounding_box($bb_polygon) ];
|
$bounding_box = [ Slic3r::Geometry::bounding_box($bb_polygon) ];
|
||||||
# $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
|
# $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
|
||||||
@ -89,7 +83,7 @@ sub fill_surface {
|
|||||||
# path is more straight
|
# path is more straight
|
||||||
my @paths = map Slic3r::Polyline->new(@$_), map @$_, @{intersection_ex(
|
my @paths = map Slic3r::Polyline->new(@$_), map @$_, @{intersection_ex(
|
||||||
$self->cache->{$cache_id},
|
$self->cache->{$cache_id},
|
||||||
[ map @$_, $expolygon->offset_ex($overlap_distance) ],
|
$expolygon,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
return { flow_spacing => $params{flow_spacing} },
|
return { flow_spacing => $params{flow_spacing} },
|
||||||
|
@ -31,8 +31,6 @@ sub fill_surface {
|
|||||||
$flow_spacing = unscale $distance_between_lines;
|
$flow_spacing = unscale $distance_between_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $overlap_distance = scale $params{flow_spacing} * &Slic3r::PERIMETER_INFILL_OVERLAP_OVER_SPACING;
|
|
||||||
|
|
||||||
my $x = $bounding_box->[X1];
|
my $x = $bounding_box->[X1];
|
||||||
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
||||||
my @vertical_lines = ();
|
my @vertical_lines = ();
|
||||||
@ -52,10 +50,6 @@ sub fill_surface {
|
|||||||
+($expolygon->offset_ex(scaled_epsilon))[0], # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
|
+($expolygon->offset_ex(scaled_epsilon))[0], # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
|
||||||
[ @vertical_lines ],
|
[ @vertical_lines ],
|
||||||
) };
|
) };
|
||||||
for (@paths) {
|
|
||||||
$_->[0][Y] += $overlap_distance;
|
|
||||||
$_->[-1][Y] -= $overlap_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
# connect lines
|
# connect lines
|
||||||
unless ($params{dont_connect}) {
|
unless ($params{dont_connect}) {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package Slic3r::Flow;
|
package Slic3r::Flow;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
use List::Util qw(max);
|
|
||||||
use Slic3r::Geometry qw(PI scale);
|
use Slic3r::Geometry qw(PI scale);
|
||||||
|
|
||||||
has 'nozzle_diameter' => (is => 'ro', required => 1);
|
has 'nozzle_diameter' => (is => 'ro', required => 1);
|
||||||
has 'layer_height' => (is => 'ro', default => sub { $Slic3r::Config->layer_height });
|
has 'layer_height' => (is => 'ro', default => sub { $Slic3r::Config->layer_height });
|
||||||
|
has 'role' => (is => 'ro', default => sub { '' });
|
||||||
|
|
||||||
has 'width' => (is => 'rwp', builder => 1);
|
has 'width' => (is => 'rwp', builder => 1);
|
||||||
has 'spacing' => (is => 'lazy');
|
has 'spacing' => (is => 'lazy');
|
||||||
@ -36,12 +36,13 @@ sub _build_width {
|
|||||||
$width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
|
$width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $min = max(
|
my $min = $self->nozzle_diameter * 1.05;
|
||||||
($volume / $self->layer_height),
|
my $max;
|
||||||
($self->nozzle_diameter * 1.05),
|
if ($self->role ne 'infill') {
|
||||||
);
|
# do not limit width for sparse infill so that we use full native flow for it
|
||||||
my $max = $self->nozzle_diameter * 2;
|
$max = $self->nozzle_diameter * 1.7;
|
||||||
$width = $max if $width > $max;
|
}
|
||||||
|
$width = $max if defined($max) && $width > $max;
|
||||||
$width = $min if $width < $min;
|
$width = $min if $width < $min;
|
||||||
|
|
||||||
return $width;
|
return $width;
|
||||||
|
@ -53,6 +53,7 @@ my %role_speeds = (
|
|||||||
&EXTR_ROLE_SOLIDFILL => 'solid_infill',
|
&EXTR_ROLE_SOLIDFILL => 'solid_infill',
|
||||||
&EXTR_ROLE_TOPSOLIDFILL => 'top_solid_infill',
|
&EXTR_ROLE_TOPSOLIDFILL => 'top_solid_infill',
|
||||||
&EXTR_ROLE_BRIDGE => 'bridge',
|
&EXTR_ROLE_BRIDGE => 'bridge',
|
||||||
|
&EXTR_ROLE_INTERNALBRIDGE => 'solid_infill',
|
||||||
&EXTR_ROLE_SKIRT => 'perimeter',
|
&EXTR_ROLE_SKIRT => 'perimeter',
|
||||||
&EXTR_ROLE_SUPPORTMATERIAL => 'support_material',
|
&EXTR_ROLE_SUPPORTMATERIAL => 'support_material',
|
||||||
&EXTR_ROLE_GAPFILL => 'gap_fill',
|
&EXTR_ROLE_GAPFILL => 'gap_fill',
|
||||||
@ -203,13 +204,13 @@ sub extrude_path {
|
|||||||
$acceleration = $Slic3r::Config->perimeter_acceleration;
|
$acceleration = $Slic3r::Config->perimeter_acceleration;
|
||||||
} elsif ($Slic3r::Config->infill_acceleration && $path->is_fill) {
|
} elsif ($Slic3r::Config->infill_acceleration && $path->is_fill) {
|
||||||
$acceleration = $Slic3r::Config->infill_acceleration;
|
$acceleration = $Slic3r::Config->infill_acceleration;
|
||||||
} elsif ($Slic3r::Config->infill_acceleration && $path->role == EXTR_ROLE_BRIDGE) {
|
} elsif ($Slic3r::Config->infill_acceleration && ($path->role == EXTR_ROLE_BRIDGE || $path->role == EXTR_ROLE_INTERNALBRIDGE)) {
|
||||||
$acceleration = $Slic3r::Config->bridge_acceleration;
|
$acceleration = $Slic3r::Config->bridge_acceleration;
|
||||||
}
|
}
|
||||||
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
|
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
|
||||||
|
|
||||||
my $area; # mm^3 of extrudate per mm of tool movement
|
my $area; # mm^3 of extrudate per mm of tool movement
|
||||||
if ($path->role == EXTR_ROLE_BRIDGE) {
|
if ($path->role == EXTR_ROLE_BRIDGE || $path->role == EXTR_ROLE_INTERNALBRIDGE) {
|
||||||
my $s = $path->flow_spacing;
|
my $s = $path->flow_spacing;
|
||||||
$area = ($s**2) * PI/4;
|
$area = ($s**2) * PI/4;
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,22 +56,20 @@ sub BUILD {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# simplify islands
|
||||||
|
@{$self->islands} = map $_->simplify($self->_inner_margin), @{$self->islands};
|
||||||
|
|
||||||
# process individual islands
|
# process individual islands
|
||||||
for my $i (0 .. $#{$self->islands}) {
|
for my $i (0 .. $#{$self->islands}) {
|
||||||
# simplify the island's contours
|
|
||||||
$self->islands->[$i]->simplify($self->_inner_margin);
|
|
||||||
|
|
||||||
# offset the island inwards to make the boundaries for internal movements
|
# offset the island inwards to make the boundaries for internal movements
|
||||||
# so that no motion along external perimeters happens
|
# so that no motion along external perimeters happens
|
||||||
$self->_inner->[$i] = [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ]
|
$self->_inner->[$i] = $self->no_internal
|
||||||
if !$self->no_internal;
|
? []
|
||||||
|
: [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ];
|
||||||
|
|
||||||
# offset the island outwards to make the boundaries for external movements
|
# offset the island outwards to make the boundaries for external movements
|
||||||
$self->_outer->[$i] = [ $self->islands->[$i]->contour->offset($self->_outer_margin) ];
|
$self->_outer->[$i] = [ $self->islands->[$i]->contour->offset($self->_outer_margin) ];
|
||||||
|
|
||||||
# further simplification (isn't this a duplication of the one above?)
|
|
||||||
$_->simplify($self->_inner_margin) for @{$self->_inner->[$i]}, @{$self->_outer->[$i]};
|
|
||||||
|
|
||||||
# if internal motion is enabled, build a set of utility expolygons representing
|
# if internal motion is enabled, build a set of utility expolygons representing
|
||||||
# the outer boundaries (as contours) and the inner boundaries (as holes). whenever
|
# the outer boundaries (as contours) and the inner boundaries (as holes). whenever
|
||||||
# we jump from a hole to a contour or viceversa, we know we're crossing a perimeter
|
# we jump from a hole to a contour or viceversa, we know we're crossing a perimeter
|
||||||
|
@ -1137,9 +1137,8 @@ sub make_thumbnail {
|
|||||||
for (map @$_, map @$_, @{$thumbnail->expolygons}) {
|
for (map @$_, map @$_, @{$thumbnail->expolygons}) {
|
||||||
@$_ = map $_ * $self->thumbnail_scaling_factor, @$_;
|
@$_ = map $_ * $self->thumbnail_scaling_factor, @$_;
|
||||||
}
|
}
|
||||||
|
@{$thumbnail->expolygons} = map $_->simplify(0.5), grep $_->area >= 1, @{$thumbnail->expolygons};
|
||||||
foreach my $expolygon (@{$thumbnail->expolygons}) {
|
foreach my $expolygon (@{$thumbnail->expolygons}) {
|
||||||
@$expolygon = grep $_->area >= 1, @$expolygon;
|
|
||||||
$expolygon->simplify(0.5);
|
|
||||||
$expolygon->rotate(Slic3r::Geometry::deg2rad($self->rotate));
|
$expolygon->rotate(Slic3r::Geometry::deg2rad($self->rotate));
|
||||||
$expolygon->scale($self->scale);
|
$expolygon->scale($self->scale);
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ sub build {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title => 'Advanced',
|
title => 'Advanced',
|
||||||
options => [qw(avoid_crossing_perimeters)],
|
options => [qw(avoid_crossing_perimeters external_perimeters_first)],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -511,16 +511,16 @@ sub build {
|
|||||||
{
|
{
|
||||||
title => 'Extrusion width',
|
title => 'Extrusion width',
|
||||||
label_width => 180,
|
label_width => 180,
|
||||||
options => [qw(extrusion_width first_layer_extrusion_width perimeter_extrusion_width infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width)],
|
options => [qw(extrusion_width first_layer_extrusion_width perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title => 'Flow',
|
title => 'Flow',
|
||||||
options => [qw(bridge_flow_ratio)],
|
options => [qw(bridge_flow_ratio)],
|
||||||
},
|
},
|
||||||
$Slic3r::have_threads ? {
|
{
|
||||||
title => 'Other',
|
title => 'Other',
|
||||||
options => [qw(threads)],
|
options => [($Slic3r::have_threads ? qw(threads) : ()), qw(resolution)],
|
||||||
} : (),
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ our @EXPORT_OK = qw(
|
|||||||
point_is_on_left_of_segment polyline_lines polygon_lines nearest_point
|
point_is_on_left_of_segment polyline_lines polygon_lines nearest_point
|
||||||
point_along_segment polygon_segment_having_point polygon_has_subsegment
|
point_along_segment polygon_segment_having_point polygon_has_subsegment
|
||||||
polygon_has_vertex polyline_length can_connect_points deg2rad rad2deg
|
polygon_has_vertex polyline_length can_connect_points deg2rad rad2deg
|
||||||
rotate_points move_points remove_coinciding_points clip_segment_polygon
|
rotate_points move_points clip_segment_polygon
|
||||||
sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
|
sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
|
||||||
line_intersection bounding_box bounding_box_intersect same_point same_line
|
line_intersection bounding_box bounding_box_intersect same_point same_line
|
||||||
longest_segment angle3points three_points_aligned line_direction
|
longest_segment angle3points three_points_aligned line_direction
|
||||||
@ -375,15 +375,6 @@ sub move_points {
|
|||||||
return map Slic3r::Point->new($shift->[X] + $_->[X], $shift->[Y] + $_->[Y]), @points;
|
return map Slic3r::Point->new($shift->[X] + $_->[X], $shift->[Y] + $_->[Y]), @points;
|
||||||
}
|
}
|
||||||
|
|
||||||
# preserves order
|
|
||||||
sub remove_coinciding_points {
|
|
||||||
my ($points) = @_;
|
|
||||||
|
|
||||||
my %p = map { sprintf('%f,%f', @$_) => "$_" } @$points;
|
|
||||||
%p = reverse %p;
|
|
||||||
@$points = grep $p{"$_"}, @$points;
|
|
||||||
}
|
|
||||||
|
|
||||||
# implementation of Liang-Barsky algorithm
|
# implementation of Liang-Barsky algorithm
|
||||||
# polygon must be convex and ccw
|
# polygon must be convex and ccw
|
||||||
sub clip_segment_polygon {
|
sub clip_segment_polygon {
|
||||||
|
@ -100,4 +100,14 @@ sub collapse_ex {
|
|||||||
return union_ex([@result]);
|
return union_ex([@result]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub simplify_polygon {
|
||||||
|
my ($polygon, $pft) = @_;
|
||||||
|
return @{ Math::Clipper::simplify_polygon($polygon, $pft // PFT_NONZERO) };
|
||||||
|
}
|
||||||
|
|
||||||
|
sub simplify_polygons {
|
||||||
|
my ($polygons, $pft) = @_;
|
||||||
|
return @{ Math::Clipper::simplify_polygons($polygons, $pft // PFT_NONZERO) };
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -16,6 +16,7 @@ has 'layer' => (
|
|||||||
has 'region' => (is => 'ro', required => 1, handles => [qw(extruders)]);
|
has 'region' => (is => 'ro', required => 1, handles => [qw(extruders)]);
|
||||||
has 'perimeter_flow' => (is => 'rw');
|
has 'perimeter_flow' => (is => 'rw');
|
||||||
has 'infill_flow' => (is => 'rw');
|
has 'infill_flow' => (is => 'rw');
|
||||||
|
has 'solid_infill_flow' => (is => 'rw');
|
||||||
has 'top_infill_flow' => (is => 'rw');
|
has 'top_infill_flow' => (is => 'rw');
|
||||||
has 'infill_area_threshold' => (is => 'lazy');
|
has 'infill_area_threshold' => (is => 'lazy');
|
||||||
has 'overhang_width' => (is => 'lazy');
|
has 'overhang_width' => (is => 'lazy');
|
||||||
@ -59,15 +60,15 @@ sub _update_flows {
|
|||||||
return if !$self->region;
|
return if !$self->region;
|
||||||
|
|
||||||
if ($self->id == 0) {
|
if ($self->id == 0) {
|
||||||
$self->perimeter_flow
|
for (qw(perimeter infill solid_infill top_infill)) {
|
||||||
($self->region->first_layer_flows->{perimeter} || $self->region->flows->{perimeter});
|
my $method = "${_}_flow";
|
||||||
$self->infill_flow
|
$self->$method
|
||||||
($self->region->first_layer_flows->{infill} || $self->region->flows->{infill});
|
($self->region->first_layer_flows->{$_} || $self->region->flows->{$_});
|
||||||
$self->top_infill_flow
|
}
|
||||||
($self->region->first_layer_flows->{top_infill} || $self->region->flows->{top_infill});
|
|
||||||
} else {
|
} else {
|
||||||
$self->perimeter_flow($self->region->flows->{perimeter});
|
$self->perimeter_flow($self->region->flows->{perimeter});
|
||||||
$self->infill_flow($self->region->flows->{infill});
|
$self->infill_flow($self->region->flows->{infill});
|
||||||
|
$self->solid_infill_flow($self->region->flows->{solid_infill});
|
||||||
$self->top_infill_flow($self->region->flows->{top_infill});
|
$self->top_infill_flow($self->region->flows->{top_infill});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ sub _build_overhang_width {
|
|||||||
|
|
||||||
sub _build_infill_area_threshold {
|
sub _build_infill_area_threshold {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return $self->infill_flow->scaled_spacing ** 2;
|
return $self->solid_infill_flow->scaled_spacing ** 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
# build polylines from lines
|
# build polylines from lines
|
||||||
@ -160,7 +161,7 @@ sub make_perimeters {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $perimeter_spacing = $self->perimeter_flow->scaled_spacing;
|
my $perimeter_spacing = $self->perimeter_flow->scaled_spacing;
|
||||||
my $infill_spacing = $self->infill_flow->scaled_spacing;
|
my $infill_spacing = $self->solid_infill_flow->scaled_spacing;
|
||||||
my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2;
|
my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2;
|
||||||
|
|
||||||
# this array will hold one arrayref per original surface (island);
|
# this array will hold one arrayref per original surface (island);
|
||||||
@ -263,14 +264,14 @@ sub make_perimeters {
|
|||||||
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||||
# and then we offset back and forth by the infill spacing to only consider the
|
# and then we offset back and forth by the infill spacing to only consider the
|
||||||
# non-collapsing regions
|
# non-collapsing regions
|
||||||
my @fill_boundaries = @{union_ex([
|
push @{ $self->fill_surfaces },
|
||||||
|
map $_->simplify(&Slic3r::SCALED_RESOLUTION),
|
||||||
|
@{union_ex([
|
||||||
Slic3r::Geometry::Clipper::offset(
|
Slic3r::Geometry::Clipper::offset(
|
||||||
[Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))],
|
[Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))],
|
||||||
+$infill_spacing,
|
+$infill_spacing,
|
||||||
),
|
),
|
||||||
])};
|
])};
|
||||||
$_->simplify(&Slic3r::SCALED_RESOLUTION) for @fill_boundaries;
|
|
||||||
push @{ $self->fill_surfaces }, @fill_boundaries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# fill gaps
|
# fill gaps
|
||||||
@ -404,10 +405,14 @@ sub make_perimeters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# do holes, then contours starting from innermost one
|
# first do holes
|
||||||
$self->_add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef)
|
$self->_add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef)
|
||||||
for reverse 0 .. $#holes;
|
for reverse 0 .. $#holes;
|
||||||
for my $depth (reverse 0 .. $#$island) {
|
|
||||||
|
# then do contours according to the user settings
|
||||||
|
my @contour_order = 0 .. $#$island;
|
||||||
|
@contour_order = reverse @contour_order if !$Slic3r::Config->external_perimeters_first;
|
||||||
|
for my $depth (@contour_order) {
|
||||||
my $role = $depth == $#$island ? EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER
|
my $role = $depth == $#$island ? EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER
|
||||||
: $depth == 0 ? EXTR_ROLE_EXTERNAL_PERIMETER
|
: $depth == 0 ? EXTR_ROLE_EXTERNAL_PERIMETER
|
||||||
: EXTR_ROLE_PERIMETER;
|
: EXTR_ROLE_PERIMETER;
|
||||||
|
@ -6,9 +6,22 @@ use warnings;
|
|||||||
use parent 'Slic3r::Polyline';
|
use parent 'Slic3r::Polyline';
|
||||||
|
|
||||||
use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges
|
use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges
|
||||||
polygon_remove_acute_vertices polygon_segment_having_point point_in_polygon);
|
polygon_remove_acute_vertices polygon_segment_having_point point_in_polygon
|
||||||
|
X1 X2 Y1 Y2);
|
||||||
use Slic3r::Geometry::Clipper qw(JT_MITER);
|
use Slic3r::Geometry::Clipper qw(JT_MITER);
|
||||||
|
|
||||||
|
sub new_from_bounding_box {
|
||||||
|
my $class = shift;
|
||||||
|
my ($bounding_box) = @_;
|
||||||
|
|
||||||
|
return $class->new([
|
||||||
|
[ $bounding_box->[X1], $bounding_box->[Y1] ],
|
||||||
|
[ $bounding_box->[X2], $bounding_box->[Y1] ],
|
||||||
|
[ $bounding_box->[X2], $bounding_box->[Y2] ],
|
||||||
|
[ $bounding_box->[X1], $bounding_box->[Y2] ],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
sub lines {
|
sub lines {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return polygon_lines($self);
|
return polygon_lines($self);
|
||||||
@ -97,6 +110,11 @@ sub grow {
|
|||||||
return $self->split_at_first_point->grow(@_);
|
return $self->split_at_first_point->grow(@_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub simplify {
|
||||||
|
my $self = shift;
|
||||||
|
return Slic3r::Geometry::Clipper::simplify_polygon( $self->SUPER::simplify(@_) );
|
||||||
|
}
|
||||||
|
|
||||||
# this method subdivides the polygon segments to that no one of them
|
# this method subdivides the polygon segments to that no one of them
|
||||||
# is longer than the length provided
|
# is longer than the length provided
|
||||||
sub subdivide {
|
sub subdivide {
|
||||||
|
@ -68,8 +68,8 @@ sub simplify {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $tolerance = shift || 10;
|
my $tolerance = shift || 10;
|
||||||
|
|
||||||
@$self = @{ Boost::Geometry::Utils::linestring_simplify($self, $tolerance) };
|
my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance);
|
||||||
bless $_, 'Slic3r::Point' for @$self;
|
return (ref $self)->new($simplified);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub reverse {
|
sub reverse {
|
||||||
|
@ -134,7 +134,7 @@ sub add_model {
|
|||||||
|
|
||||||
if ($object->instances) {
|
if ($object->instances) {
|
||||||
# replace the default [0,0] instance with the custom ones
|
# replace the default [0,0] instance with the custom ones
|
||||||
@{$print_object->copies} = map [ scale $_->offset->[X], scale $_->offset->[Y] ], @{$object->instances};
|
$print_object->copies([ map [ scale $_->offset->[X], scale $_->offset->[Y] ], @{$object->instances} ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,17 +201,20 @@ sub init_extruders {
|
|||||||
my $region = $self->regions->[$region_id];
|
my $region = $self->regions->[$region_id];
|
||||||
|
|
||||||
# per-role extruders and flows
|
# per-role extruders and flows
|
||||||
for (qw(perimeter infill top_infill)) {
|
for (qw(perimeter infill solid_infill top_infill)) {
|
||||||
my $extruder_name = $_ eq 'top_infill' ? 'infill' : $_;
|
my $extruder_name = $_;
|
||||||
|
$extruder_name =~ s/^(?:solid|top)_//;
|
||||||
$region->extruders->{$_} = ($self->regions_count > 1)
|
$region->extruders->{$_} = ($self->regions_count > 1)
|
||||||
? $self->extruders->[$extruder_mapping{$region_id}]
|
? $self->extruders->[$extruder_mapping{$region_id}]
|
||||||
: $self->extruders->[$self->config->get("${extruder_name}_extruder")-1];
|
: $self->extruders->[$self->config->get("${extruder_name}_extruder")-1];
|
||||||
$region->flows->{$_} = $region->extruders->{$_}->make_flow(
|
$region->flows->{$_} = $region->extruders->{$_}->make_flow(
|
||||||
width => $self->config->get("${_}_extrusion_width") || $self->config->extrusion_width,
|
width => $self->config->get("${_}_extrusion_width") || $self->config->extrusion_width,
|
||||||
|
role => $_,
|
||||||
);
|
);
|
||||||
$region->first_layer_flows->{$_} = $region->extruders->{$_}->make_flow(
|
$region->first_layer_flows->{$_} = $region->extruders->{$_}->make_flow(
|
||||||
layer_height => $self->config->get_value('first_layer_height'),
|
layer_height => $self->config->get_value('first_layer_height'),
|
||||||
width => $self->config->first_layer_extrusion_width,
|
width => $self->config->first_layer_extrusion_width,
|
||||||
|
role => $_,
|
||||||
) if $self->config->first_layer_extrusion_width;
|
) if $self->config->first_layer_extrusion_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,10 +224,12 @@ sub init_extruders {
|
|||||||
my $extruder = $self->extruders->[$self->config->support_material_extruder-1];
|
my $extruder = $self->extruders->[$self->config->support_material_extruder-1];
|
||||||
$self->support_material_flow($extruder->make_flow(
|
$self->support_material_flow($extruder->make_flow(
|
||||||
width => $self->config->support_material_extrusion_width || $self->config->extrusion_width,
|
width => $self->config->support_material_extrusion_width || $self->config->extrusion_width,
|
||||||
|
role => 'support_material',
|
||||||
));
|
));
|
||||||
$self->first_layer_support_material_flow($extruder->make_flow(
|
$self->first_layer_support_material_flow($extruder->make_flow(
|
||||||
layer_height => $self->config->get_value('first_layer_height'),
|
layer_height => $self->config->get_value('first_layer_height'),
|
||||||
width => $self->config->first_layer_extrusion_width,
|
width => $self->config->first_layer_extrusion_width,
|
||||||
|
role => 'support_material',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,6 +318,16 @@ sub size {
|
|||||||
return [ $bb[X2] - $bb[X1], $bb[Y2] - $bb[Y1] ];
|
return [ $bb[X2] - $bb[X1], $bb[Y2] - $bb[Y1] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _simplify_slices {
|
||||||
|
my $self = shift;
|
||||||
|
my ($distance) = @_;
|
||||||
|
|
||||||
|
foreach my $layer (map @{$_->layers}, @{$self->objects}) {
|
||||||
|
@$_ = map $_->simplify($distance), @$_
|
||||||
|
for $layer->slices, (map $_->slices, @{$layer->regions});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub export_gcode {
|
sub export_gcode {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
@ -324,7 +339,12 @@ sub export_gcode {
|
|||||||
# skein the STL into layers
|
# skein the STL into layers
|
||||||
# each layer has surfaces with holes
|
# each layer has surfaces with holes
|
||||||
$status_cb->(10, "Processing triangulated mesh");
|
$status_cb->(10, "Processing triangulated mesh");
|
||||||
$_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects};
|
$_->slice for @{$self->objects};
|
||||||
|
|
||||||
|
if ($Slic3r::Config->resolution) {
|
||||||
|
$status_cb->(15, "Simplifying input");
|
||||||
|
$self->_simplify_slices(scale $Slic3r::Config->resolution);
|
||||||
|
}
|
||||||
|
|
||||||
# make perimeters
|
# make perimeters
|
||||||
# this will add a set of extrusion loops to each layer
|
# this will add a set of extrusion loops to each layer
|
||||||
@ -334,10 +354,7 @@ sub export_gcode {
|
|||||||
|
|
||||||
# simplify slices (both layer and region slices),
|
# simplify slices (both layer and region slices),
|
||||||
# we only need the max resolution for perimeters
|
# we only need the max resolution for perimeters
|
||||||
foreach my $layer (map @{$_->layers}, @{$self->objects}) {
|
$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
|
||||||
$_->simplify(&Slic3r::SCALED_RESOLUTION)
|
|
||||||
for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions});
|
|
||||||
}
|
|
||||||
|
|
||||||
# this will assign a type (top/bottom/internal) to $layerm->slices
|
# this will assign a type (top/bottom/internal) to $layerm->slices
|
||||||
# and transform $layerm->fill_surfaces from expolygon
|
# and transform $layerm->fill_surfaces from expolygon
|
||||||
@ -477,7 +494,7 @@ sub export_svg {
|
|||||||
# calls ->perimeter_flow
|
# calls ->perimeter_flow
|
||||||
$self->init_extruders;
|
$self->init_extruders;
|
||||||
|
|
||||||
$_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects};
|
$_->slice for @{$self->objects};
|
||||||
$self->arrange_objects;
|
$self->arrange_objects;
|
||||||
|
|
||||||
my $output_file = $self->expanded_output_filepath($params{output_file});
|
my $output_file = $self->expanded_output_filepath($params{output_file});
|
||||||
@ -684,6 +701,8 @@ sub write_gcode {
|
|||||||
}
|
}
|
||||||
printf $fh "; perimeters extrusion width = %.2fmm\n", $self->regions->[0]->flows->{perimeter}->width;
|
printf $fh "; perimeters extrusion width = %.2fmm\n", $self->regions->[0]->flows->{perimeter}->width;
|
||||||
printf $fh "; infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{infill}->width;
|
printf $fh "; infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{infill}->width;
|
||||||
|
printf $fh "; solid infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{solid_infill}->width;
|
||||||
|
printf $fh "; top infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{top_infill}->width;
|
||||||
printf $fh "; support material extrusion width = %.2fmm\n", $self->support_material_flow->width
|
printf $fh "; support material extrusion width = %.2fmm\n", $self->support_material_flow->width
|
||||||
if $self->support_material_flow;
|
if $self->support_material_flow;
|
||||||
printf $fh "; first layer extrusion width = %.2fmm\n", $self->regions->[0]->first_layer_flows->{perimeter}->width
|
printf $fh "; first layer extrusion width = %.2fmm\n", $self->regions->[0]->first_layer_flows->{perimeter}->width
|
||||||
|
@ -3,7 +3,7 @@ use Moo;
|
|||||||
|
|
||||||
use List::Util qw(min sum first);
|
use List::Util qw(min sum first);
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Geometry qw(Z PI scale unscale deg2rad rad2deg scaled_epsilon);
|
use Slic3r::Geometry qw(Z PI scale unscale deg2rad rad2deg scaled_epsilon chained_path_points);
|
||||||
use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset collapse_ex);
|
use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset collapse_ex);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ has 'print' => (is => 'ro', weak_ref => 1, required => 1);
|
|||||||
has 'input_file' => (is => 'rw', required => 0);
|
has 'input_file' => (is => 'rw', required => 0);
|
||||||
has 'meshes' => (is => 'rw', default => sub { [] }); # by region_id
|
has 'meshes' => (is => 'rw', default => sub { [] }); # by region_id
|
||||||
has 'size' => (is => 'rw', required => 1);
|
has 'size' => (is => 'rw', required => 1);
|
||||||
has 'copies' => (is => 'rw', default => sub {[ [0,0] ]});
|
has 'copies' => (is => 'rw', default => sub {[ [0,0] ]}, trigger => 1);
|
||||||
has 'layers' => (is => 'rw', default => sub { [] });
|
has 'layers' => (is => 'rw', default => sub { [] });
|
||||||
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
|
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
|
||||||
|
|
||||||
@ -50,6 +50,14 @@ sub BUILD {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _trigger_copies {
|
||||||
|
my $self = shift;
|
||||||
|
return unless @{$self->copies} > 1;
|
||||||
|
|
||||||
|
# order copies with a nearest neighbor search
|
||||||
|
@{$self->copies} = @{chained_path_points($self->copies)}
|
||||||
|
}
|
||||||
|
|
||||||
sub layer_count {
|
sub layer_count {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return scalar @{ $self->layers };
|
return scalar @{ $self->layers };
|
||||||
@ -121,7 +129,7 @@ sub slice {
|
|||||||
die "Invalid input file\n" if !@{$self->layers};
|
die "Invalid input file\n" if !@{$self->layers};
|
||||||
|
|
||||||
# free memory
|
# free memory
|
||||||
$self->meshes(undef) unless $params{keep_meshes};
|
$self->meshes(undef);
|
||||||
|
|
||||||
# remove last layer if empty
|
# remove last layer if empty
|
||||||
# (we might have created it because of the $max_layer = ... + 1 code in TriangleMesh)
|
# (we might have created it because of the $max_layer = ... + 1 code in TriangleMesh)
|
||||||
@ -580,7 +588,7 @@ sub discover_horizontal_shells {
|
|||||||
# make sure the new internal solid is wide enough, as it might get collapsed when
|
# make sure the new internal solid is wide enough, as it might get collapsed when
|
||||||
# spacing is added in Fill.pm
|
# spacing is added in Fill.pm
|
||||||
{
|
{
|
||||||
my $margin = 3 * $layerm->infill_flow->scaled_width; # require at least this size
|
my $margin = 3 * $layerm->solid_infill_flow->scaled_width; # require at least this size
|
||||||
my $too_narrow = diff_ex(
|
my $too_narrow = diff_ex(
|
||||||
[ map @$_, @$new_internal_solid ],
|
[ map @$_, @$new_internal_solid ],
|
||||||
[ offset([ offset([ map @$_, @$new_internal_solid ], -$margin) ], +$margin) ],
|
[ offset([ offset([ map @$_, @$new_internal_solid ], -$margin) ], +$margin) ],
|
||||||
@ -658,7 +666,7 @@ sub combine_infill {
|
|||||||
my $nozzle_diameter = $self->print->regions->[$region_id]->extruders->{infill}->nozzle_diameter;
|
my $nozzle_diameter = $self->print->regions->[$region_id]->extruders->{infill}->nozzle_diameter;
|
||||||
|
|
||||||
# define the combinations
|
# define the combinations
|
||||||
my @combine = (); # layer_id => depth
|
my @combine = (); # layer_id => thickness in layers
|
||||||
{
|
{
|
||||||
my $current_height = my $layers = 0;
|
my $current_height = my $layers = 0;
|
||||||
for my $layer_id (1 .. $#layer_heights) {
|
for my $layer_id (1 .. $#layer_heights) {
|
||||||
@ -707,15 +715,16 @@ sub combine_infill {
|
|||||||
# so let's remove those areas from all layers
|
# so let's remove those areas from all layers
|
||||||
|
|
||||||
my @intersection_with_clearance = map $_->offset(
|
my @intersection_with_clearance = map $_->offset(
|
||||||
$layerms[-1]->infill_flow->scaled_width / 2
|
$layerms[-1]->solid_infill_flow->scaled_width / 2
|
||||||
+ $layerms[-1]->perimeter_flow->scaled_width / 2
|
+ $layerms[-1]->perimeter_flow->scaled_width / 2
|
||||||
# Because fill areas for rectilinear and honeycomb are grown
|
# Because fill areas for rectilinear and honeycomb are grown
|
||||||
# later to overlap perimeters, we need to counteract that too.
|
# later to overlap perimeters, we need to counteract that too.
|
||||||
+ (($type == S_TYPE_INTERNALSOLID || $Slic3r::Config->fill_pattern =~ /(rectilinear|honeycomb)/)
|
+ (($type == S_TYPE_INTERNALSOLID || $Slic3r::Config->fill_pattern =~ /(rectilinear|honeycomb)/)
|
||||||
? $layerms[-1]->infill_flow->scaled_width * &Slic3r::PERIMETER_INFILL_OVERLAP_OVER_SPACING
|
? $layerms[-1]->solid_infill_flow->scaled_width * &Slic3r::INFILL_OVERLAP_OVER_SPACING
|
||||||
: 0)
|
: 0)
|
||||||
), @$intersection;
|
), @$intersection;
|
||||||
|
|
||||||
|
|
||||||
foreach my $layerm (@layerms) {
|
foreach my $layerm (@layerms) {
|
||||||
my @this_type = grep $_->surface_type == $type, @{$layerm->fill_surfaces};
|
my @this_type = grep $_->surface_type == $type, @{$layerm->fill_surfaces};
|
||||||
my @other_types = grep $_->surface_type != $type, @{$layerm->fill_surfaces};
|
my @other_types = grep $_->surface_type != $type, @{$layerm->fill_surfaces};
|
||||||
@ -729,7 +738,12 @@ sub combine_infill {
|
|||||||
# apply surfaces back with adjusted depth to the uppermost layer
|
# apply surfaces back with adjusted depth to the uppermost layer
|
||||||
if ($layerm->id == $layer_id) {
|
if ($layerm->id == $layer_id) {
|
||||||
push @new_this_type,
|
push @new_this_type,
|
||||||
map Slic3r::Surface->new(expolygon => $_, surface_type => $type, depth_layers => $every),
|
map Slic3r::Surface->new(
|
||||||
|
expolygon => $_,
|
||||||
|
surface_type => $type,
|
||||||
|
thickness => sum(map $_->height, @layerms),
|
||||||
|
thickness_layers => scalar(@layerms),
|
||||||
|
),
|
||||||
@$intersection;
|
@$intersection;
|
||||||
} else {
|
} else {
|
||||||
# save void surfaces
|
# save void surfaces
|
||||||
@ -789,8 +803,10 @@ sub generate_support_material {
|
|||||||
[ map @$_, @{ $upper_layers_overhangs[-1] || [] } ],
|
[ map @$_, @{ $upper_layers_overhangs[-1] || [] } ],
|
||||||
[ map @$_, @current_layer_offsetted_slices ],
|
[ map @$_, @current_layer_offsetted_slices ],
|
||||||
);
|
);
|
||||||
$layers_contact_areas{$i} = collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width);
|
$layers_contact_areas{$i} = [
|
||||||
$_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}};
|
map $_->simplify($flow->scaled_spacing),
|
||||||
|
@{collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width)},
|
||||||
|
];
|
||||||
|
|
||||||
# to define interface regions of this layer we consider the overhangs of all the upper layers
|
# to define interface regions of this layer we consider the overhangs of all the upper layers
|
||||||
# minus the first one
|
# minus the first one
|
||||||
@ -801,8 +817,10 @@ sub generate_support_material {
|
|||||||
(map @$_, @{ $layers_contact_areas{$i} }),
|
(map @$_, @{ $layers_contact_areas{$i} }),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
$layers_interfaces{$i} = collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width);
|
$layers_interfaces{$i} = [
|
||||||
$_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}};
|
map $_->simplify($flow->scaled_spacing),
|
||||||
|
@{collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width)},
|
||||||
|
];
|
||||||
|
|
||||||
# generate support material in current layer (for upper layers)
|
# generate support material in current layer (for upper layers)
|
||||||
@current_support_regions = @{diff_ex(
|
@current_support_regions = @{diff_ex(
|
||||||
@ -821,8 +839,10 @@ sub generate_support_material {
|
|||||||
(map @$_, @{ $layers_interfaces{$i} }),
|
(map @$_, @{ $layers_interfaces{$i} }),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
$layers{$i} = collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width);
|
$layers{$i} = [
|
||||||
$_->simplify($flow->scaled_spacing) for @{$layers{$i}};
|
map $_->simplify($flow->scaled_spacing),
|
||||||
|
@{collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width)},
|
||||||
|
];
|
||||||
|
|
||||||
# get layer overhangs and put them into queue for adding support inside lower layers;
|
# get layer overhangs and put them into queue for adding support inside lower layers;
|
||||||
# we need an angle threshold for this
|
# we need an angle threshold for this
|
||||||
@ -835,8 +855,8 @@ sub generate_support_material {
|
|||||||
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
||||||
: $self->layers->[1]->regions->[0]->overhang_width;
|
: $self->layers->[1]->regions->[0]->overhang_width;
|
||||||
|
|
||||||
@overhangs = map $_->offset_ex(2 * $distance), @{diff_ex(
|
@overhangs = map $_->offset_ex(+$distance), @{diff_ex(
|
||||||
[ map @$_, map $_->offset_ex(-$distance), @{$layer->slices} ],
|
[ map @$_, @{$layer->slices} ],
|
||||||
[ map @$_, @{$lower_layer->slices} ],
|
[ map @$_, @{$lower_layer->slices} ],
|
||||||
1,
|
1,
|
||||||
)};
|
)};
|
||||||
@ -858,7 +878,7 @@ sub generate_support_material {
|
|||||||
{
|
{
|
||||||
# 0.5 ensures the paths don't get clipped externally when applying them to layers
|
# 0.5 ensures the paths don't get clipped externally when applying them to layers
|
||||||
my @areas = map $_->offset_ex(- 0.5 * $flow->scaled_width),
|
my @areas = map $_->offset_ex(- 0.5 * $flow->scaled_width),
|
||||||
@{union_ex([ map $_->contour, map @$_, values %layers ])};
|
@{union_ex([ map $_->contour, map @$_, values %layers, values %layers_interfaces, values %layers_contact_areas ])};
|
||||||
|
|
||||||
my $pattern = $Slic3r::Config->support_material_pattern;
|
my $pattern = $Slic3r::Config->support_material_pattern;
|
||||||
my @angles = ($Slic3r::Config->support_material_angle);
|
my @angles = ($Slic3r::Config->support_material_angle);
|
||||||
@ -866,7 +886,11 @@ sub generate_support_material {
|
|||||||
$pattern = 'rectilinear';
|
$pattern = 'rectilinear';
|
||||||
push @angles, $angles[0] + 90;
|
push @angles, $angles[0] + 90;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $filler = Slic3r::Fill->filler($pattern);
|
my $filler = Slic3r::Fill->filler($pattern);
|
||||||
|
$filler->bounding_box([ Slic3r::Geometry::bounding_box([ map @$_, map @$_, @areas ]) ])
|
||||||
|
if $filler->can('bounding_box');
|
||||||
|
|
||||||
my $make_pattern = sub {
|
my $make_pattern = sub {
|
||||||
my ($expolygon, $density) = @_;
|
my ($expolygon, $density) = @_;
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@ our %EXPORT_TAGS = (types => \@EXPORT_OK);
|
|||||||
|
|
||||||
use constant S_EXPOLYGON => 0;
|
use constant S_EXPOLYGON => 0;
|
||||||
use constant S_SURFACE_TYPE => 1;
|
use constant S_SURFACE_TYPE => 1;
|
||||||
use constant S_DEPTH_LAYERS => 2;
|
use constant S_THICKNESS => 2; # in mm
|
||||||
use constant S_BRIDGE_ANGLE => 3;
|
use constant S_THICKNESS_LAYERS => 3; # in layers
|
||||||
use constant S_EXTRA_PERIMETERS => 4;
|
use constant S_BRIDGE_ANGLE => 4;
|
||||||
|
use constant S_EXTRA_PERIMETERS => 5;
|
||||||
|
|
||||||
use constant S_TYPE_TOP => 0;
|
use constant S_TYPE_TOP => 0;
|
||||||
use constant S_TYPE_BOTTOM => 1;
|
use constant S_TYPE_BOTTOM => 1;
|
||||||
@ -25,9 +26,9 @@ sub new {
|
|||||||
my %args = @_;
|
my %args = @_;
|
||||||
|
|
||||||
my $self = [
|
my $self = [
|
||||||
map delete $args{$_}, qw(expolygon surface_type depth_layers bridge_angle extra_perimeters),
|
map delete $args{$_}, qw(expolygon surface_type thickness thickness_layers bridge_angle extra_perimeters),
|
||||||
];
|
];
|
||||||
$self->[S_DEPTH_LAYERS] //= 1; #/
|
$self->[$_] //= 1 for S_THICKNESS, S_THICKNESS_LAYERS;
|
||||||
|
|
||||||
bless $self, $class;
|
bless $self, $class;
|
||||||
$self;
|
$self;
|
||||||
@ -35,7 +36,8 @@ sub new {
|
|||||||
|
|
||||||
sub expolygon { $_[0][S_EXPOLYGON] }
|
sub expolygon { $_[0][S_EXPOLYGON] }
|
||||||
sub surface_type { $_[0][S_SURFACE_TYPE] = $_[1] if defined $_[1]; $_[0][S_SURFACE_TYPE] }
|
sub surface_type { $_[0][S_SURFACE_TYPE] = $_[1] if defined $_[1]; $_[0][S_SURFACE_TYPE] }
|
||||||
sub depth_layers { $_[0][S_DEPTH_LAYERS] } # this integer represents the thickness of the surface expressed in layers
|
sub thickness { $_[0][S_THICKNESS] }
|
||||||
|
sub thickness_layers { $_[0][S_THICKNESS_LAYERS] }
|
||||||
sub bridge_angle { $_[0][S_BRIDGE_ANGLE] = $_[1] if defined $_[1]; $_[0][S_BRIDGE_ANGLE] }
|
sub bridge_angle { $_[0][S_BRIDGE_ANGLE] = $_[1] if defined $_[1]; $_[0][S_BRIDGE_ANGLE] }
|
||||||
sub extra_perimeters { $_[0][S_EXTRA_PERIMETERS] = $_[1] if defined $_[1]; $_[0][S_EXTRA_PERIMETERS] }
|
sub extra_perimeters { $_[0][S_EXTRA_PERIMETERS] = $_[1] if defined $_[1]; $_[0][S_EXTRA_PERIMETERS] }
|
||||||
|
|
||||||
@ -46,7 +48,8 @@ if (eval "use Class::XSAccessor::Array; 1") {
|
|||||||
},
|
},
|
||||||
accessors => {
|
accessors => {
|
||||||
surface_type => S_SURFACE_TYPE,
|
surface_type => S_SURFACE_TYPE,
|
||||||
depth_layers => S_DEPTH_LAYERS,
|
thickness => S_THICKNESS,
|
||||||
|
thickness_layers => S_THICKNESS_LAYERS,
|
||||||
bridge_angle => S_BRIDGE_ANGLE,
|
bridge_angle => S_BRIDGE_ANGLE,
|
||||||
extra_perimeters => S_EXTRA_PERIMETERS,
|
extra_perimeters => S_EXTRA_PERIMETERS,
|
||||||
},
|
},
|
||||||
@ -60,7 +63,7 @@ sub lines { $_[0]->expolygon->lines }
|
|||||||
sub contour { $_[0]->expolygon->contour }
|
sub contour { $_[0]->expolygon->contour }
|
||||||
sub holes { $_[0]->expolygon->holes }
|
sub holes { $_[0]->expolygon->holes }
|
||||||
|
|
||||||
# static method to group surfaces having same surface_type, bridge_angle and depth_layers
|
# static method to group surfaces having same surface_type, bridge_angle and thickness*
|
||||||
sub group {
|
sub group {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $params = ref $_[0] eq 'HASH' ? shift(@_) : {};
|
my $params = ref $_[0] eq 'HASH' ? shift(@_) : {};
|
||||||
@ -68,11 +71,11 @@ sub group {
|
|||||||
|
|
||||||
my %unique_types = ();
|
my %unique_types = ();
|
||||||
foreach my $surface (@surfaces) {
|
foreach my $surface (@surfaces) {
|
||||||
my $type = ($params->{merge_solid} && $surface->is_solid)
|
my $type = join '_',
|
||||||
? 'solid'
|
($params->{merge_solid} && $surface->is_solid) ? 'solid' : $surface->surface_type,
|
||||||
: $surface->surface_type;
|
($surface->bridge_angle // ''),
|
||||||
$type .= "_" . ($surface->bridge_angle // ''); #/
|
$surface->thickness,
|
||||||
$type .= "_" . $surface->depth_layers;
|
$surface->thickness_layers;
|
||||||
$unique_types{$type} ||= [];
|
$unique_types{$type} ||= [];
|
||||||
push @{ $unique_types{$type} }, $surface;
|
push @{ $unique_types{$type} }, $surface;
|
||||||
}
|
}
|
||||||
@ -82,12 +85,22 @@ sub group {
|
|||||||
|
|
||||||
sub offset {
|
sub offset {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return map {
|
return map $self->_inflate_expolygon($_), $self->expolygon->offset_ex(@_);
|
||||||
(ref $self)->new(
|
}
|
||||||
expolygon => $_,
|
|
||||||
map { $_ => $self->$_ } qw(surface_type depth_layers bridge_angle),
|
sub simplify {
|
||||||
)
|
my $self = shift;
|
||||||
} $self->expolygon->offset_ex(@_);
|
return map $self->_inflate_expolygon($_), $self->expolygon->simplify(@_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _inflate_expolygon {
|
||||||
|
my $self = shift;
|
||||||
|
my ($expolygon) = @_;
|
||||||
|
|
||||||
|
return (ref $self)->new(
|
||||||
|
expolygon => $expolygon,
|
||||||
|
map { $_ => $self->$_ } qw(surface_type thickness thickness_layers bridge_angle),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub p {
|
sub p {
|
||||||
|
@ -250,6 +250,7 @@ $j
|
|||||||
--extra-perimeters Add more perimeters when needed (default: yes)
|
--extra-perimeters Add more perimeters when needed (default: yes)
|
||||||
--randomize-start Randomize starting point across layers (default: yes)
|
--randomize-start Randomize starting point across layers (default: yes)
|
||||||
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
||||||
|
--external-perimeters-first Reverse perimeter order. (default: no)
|
||||||
--only-retract-when-crossing-perimeters
|
--only-retract-when-crossing-perimeters
|
||||||
Disable retraction when travelling between infill paths inside the same island.
|
Disable retraction when travelling between infill paths inside the same island.
|
||||||
(default: no)
|
(default: no)
|
||||||
@ -341,6 +342,7 @@ $j
|
|||||||
|
|
||||||
Miscellaneous options:
|
Miscellaneous options:
|
||||||
--notes Notes to be added as comments to the output file
|
--notes Notes to be added as comments to the output file
|
||||||
|
--resolution Minimum detail resolution (mm, set zero for full resolution, default: $config->{resolution})
|
||||||
|
|
||||||
Flow options (advanced):
|
Flow options (advanced):
|
||||||
--extrusion-width Set extrusion width manually; it accepts either an absolute value in mm
|
--extrusion-width Set extrusion width manually; it accepts either an absolute value in mm
|
||||||
@ -351,6 +353,8 @@ $j
|
|||||||
Set a different extrusion width for perimeters
|
Set a different extrusion width for perimeters
|
||||||
--infill-extrusion-width
|
--infill-extrusion-width
|
||||||
Set a different extrusion width for infill
|
Set a different extrusion width for infill
|
||||||
|
--solid-infill-extrusion-width
|
||||||
|
Set a different extrusion width for solid infill
|
||||||
--top-infill-extrusion-width
|
--top-infill-extrusion-width
|
||||||
Set a different extrusion width for top infill
|
Set a different extrusion width for top infill
|
||||||
--support-material-extrusion-width
|
--support-material-extrusion-width
|
||||||
|
@ -2,7 +2,7 @@ use Test::More;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
plan tests => 6;
|
plan tests => 7;
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use FindBin;
|
use FindBin;
|
||||||
@ -24,7 +24,7 @@ use Slic3r;
|
|||||||
my $polyline = Slic3r::Polyline->new([
|
my $polyline = Slic3r::Polyline->new([
|
||||||
[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0],
|
[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0],
|
||||||
]);
|
]);
|
||||||
$polyline->simplify(1);
|
$polyline = $polyline->simplify(1);
|
||||||
is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker';
|
is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ use Slic3r;
|
|||||||
[0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5],
|
[0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5],
|
||||||
]);
|
]);
|
||||||
$polyline->scale(100);
|
$polyline->scale(100);
|
||||||
$polyline->simplify(25);
|
$polyline = $polyline->simplify(25);
|
||||||
is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker';
|
is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +75,10 @@ use Slic3r;
|
|||||||
ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines';
|
ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines';
|
||||||
|
|
||||||
my $num_points = scalar @$polygon;
|
my $num_points = scalar @$polygon;
|
||||||
$polygon->simplify;
|
my @simplified = $polygon->simplify;
|
||||||
note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@$polygon);
|
ok @simplified == 1, 'gear simplified to a single polygon';
|
||||||
ok @$polygon < $num_points, 'gear was further simplified using Douglas-Peucker';
|
note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified[0]});
|
||||||
|
ok @{$simplified[0]} < $num_points, 'gear was further simplified using Douglas-Peucker';
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -40,11 +40,11 @@ use Slic3r::Test;
|
|||||||
# copy of Print::export_gcode() up to the point
|
# copy of Print::export_gcode() up to the point
|
||||||
# after fill surfaces are combined
|
# after fill surfaces are combined
|
||||||
$self->init_extruders;
|
$self->init_extruders;
|
||||||
$_->slice(keep_meshes => 1) for @{$self->objects};
|
$_->slice for @{$self->objects};
|
||||||
$_->make_perimeters for @{$self->objects};
|
$_->make_perimeters for @{$self->objects};
|
||||||
foreach my $layer (map @{$_->layers}, @{$self->objects}) {
|
foreach my $layer (map @{$_->layers}, @{$self->objects}) {
|
||||||
$_->simplify(&Slic3r::SCALED_RESOLUTION)
|
@$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_
|
||||||
for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions});
|
for $layer->slices, (map $_->slices, @{$layer->regions});
|
||||||
}
|
}
|
||||||
$_->detect_surfaces_type for @{$self->objects};
|
$_->detect_surfaces_type for @{$self->objects};
|
||||||
$_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
|
$_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
|
||||||
|
Loading…
Reference in New Issue
Block a user