Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2016-10-16 17:30:56 +0300
committerbubnikv <bubnikv@gmail.com>2016-10-16 17:30:56 +0300
commit7d7f093120df5fcdfd1f9b21fc6b0622636a7ff1 (patch)
tree629a535ccdb2e4de749de28ea8a34c5a6b27d5c9 /lib
parent8f40d9b34ea75c5e772dfb4aab18554c49536f8c (diff)
C++ supports sketched, but not finalized yet. Slic3r is still using
the old Perl supports, but this time with the C++ fillers.
Diffstat (limited to 'lib')
-rw-r--r--lib/Slic3r.pm1
-rw-r--r--lib/Slic3r/Print/GCode.pm2
-rw-r--r--lib/Slic3r/Print/Object.pm36
-rw-r--r--lib/Slic3r/Print/SupportMaterial.pm124
4 files changed, 121 insertions, 42 deletions
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 1cd67fb73..ec0dae675 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -250,6 +250,7 @@ sub thread_cleanup {
*Slic3r::Print::Region::DESTROY = sub {};
*Slic3r::Surface::DESTROY = sub {};
*Slic3r::Surface::Collection::DESTROY = sub {};
+ *Slic3r::Print::SupportMaterial2::DESTROY = sub {};
*Slic3r::TriangleMesh::DESTROY = sub {};
return undef; # this prevents a "Scalars leaked" warning
}
diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm
index e862a59e1..d39241949 100644
--- a/lib/Slic3r/Print/GCode.pm
+++ b/lib/Slic3r/Print/GCode.pm
@@ -288,6 +288,8 @@ sub export {
my @obj_idx = @{chained_path([ map Slic3r::Point->new(@{$_->_shifted_copies->[0]}), @{$self->objects} ])};
# sort layers by Z
+ # All extrusion moves with the same top layer height are extruded uninterrupted,
+ # object extrusion moves are performed first, then the support.
my %layers = (); # print_z => [ [layers], [layers], [layers] ] by obj_idx
foreach my $obj_idx (0 .. ($self->print->object_count - 1)) {
my $object = $self->objects->[$obj_idx];
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 42a85e2b4..17852a528 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -70,14 +70,16 @@ sub slice {
# add raft layers
if ($self->config->raft_layers > 0) {
+ # Reserve object layers for the raft. Last layer of the raft is the contact layer.
$id += $self->config->raft_layers;
- # raise first object layer Z by the thickness of the raft itself
- # plus the extra distance required by the support material logic
+ # Raise first object layer Z by the thickness of the raft itself
+ # plus the extra distance required by the support material logic.
+ #FIXME The last raft layer is the contact layer, which shall be printed with a bridging flow for ease of separation. Currently it is not the case.
my $first_layer_height = $self->config->get_value('first_layer_height');
$print_z += $first_layer_height;
- # use a large height
+ # Use as large as possible layer height for the intermediate raft layers.
my $support_material_layer_height;
{
my @nozzle_diameters = (
@@ -90,6 +92,7 @@ sub slice {
$print_z += $support_material_layer_height * ($self->config->raft_layers - 1);
# compute the average of all nozzles used for printing the object
+ #FIXME It is expected, that the 1st layer of the object is printed with a bridging flow over a full raft. Shall it not be vice versa?
my $nozzle_diameter;
{
my @nozzle_diameters = (
@@ -664,13 +667,26 @@ sub _support_material {
bridge_flow_ratio => 0,
);
- return Slic3r::Print::SupportMaterial->new(
- print_config => $self->print->config,
- object_config => $self->config,
- first_layer_flow => $first_layer_flow,
- flow => $self->support_material_flow,
- interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
- );
+ if (1) {
+ # Old supports, Perl implementation.
+ return Slic3r::Print::SupportMaterial->new(
+ print_config => $self->print->config,
+ object_config => $self->config,
+ first_layer_flow => $first_layer_flow,
+ flow => $self->support_material_flow,
+ interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
+ );
+ } else {
+ # New supports, C++ implementation.
+ return Slic3r::Print::SupportMaterial2->new(
+ print_config => $self->print->config,
+ object_config => $self->config,
+ first_layer_flow => $first_layer_flow,
+ flow => $self->support_material_flow,
+ interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
+ soluble_interface => ($self->config->support_material_contact_distance == 0),
+ );
+ }
}
# This function analyzes slices of a region (SurfaceCollection slices).
diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm
index 69acd3251..d73677484 100644
--- a/lib/Slic3r/Print/SupportMaterial.pm
+++ b/lib/Slic3r/Print/SupportMaterial.pm
@@ -8,7 +8,7 @@ use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(epsilon scale scaled_epsilon PI rad2deg deg2rad convex_hull);
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
- intersection_pl offset2_ex diff_pl);
+ intersection_pl offset2_ex diff_pl CLIPPER_OFFSET_SCALE JT_MITER JT_ROUND);
use Slic3r::Surface ':types';
has 'print_config' => (is => 'rw', required => 1);
@@ -59,7 +59,7 @@ sub generate {
}
# Propagate contact layers downwards to generate interface layers
- my ($interface) = $self->generate_interface_layers($support_z, $contact, $top);
+ my ($interface) = $self->generate_top_interface_layers($support_z, $contact, $top);
$self->clip_with_object($interface, $support_z, $object);
$self->clip_with_shape($interface, $shape) if @$shape;
@@ -146,10 +146,14 @@ sub contact_area {
# footprint for the raft
# we only consider contours and discard holes to get a more continuous raft
push @overhang, map $_->clone, map $_->contour, @{$layer->slices};
+ # Extend by SUPPORT_MATERIAL_MARGIN, which is 1.5mm
+ # MARGIN is the C++ Slic3r::SUPPORT_MATERIAL_MARGIN constant.
push @contact, @{offset(\@overhang, scale +MARGIN)};
} else {
my $lower_layer = $object->get_layer($layer_id-1);
foreach my $layerm (@{$layer->regions}) {
+ # Extrusion width accounts for the roundings of the extrudates.
+ # It is the maximum widh of the extrudate.
my $fw = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width;
my $diff;
@@ -161,6 +165,7 @@ sub contact_area {
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
: 0;
+ # Shrinking the supported layer by layer_height/atan(threshold_rad).
$diff = diff(
offset([ map $_->p, @{$layerm->slices} ], -$d),
[ map @$_, @{$lower_layer->slices} ],
@@ -175,9 +180,12 @@ sub contact_area {
[ map @$_, @{$lower_layer->slices} ],
) if $d > $fw/2;
} else {
+ # Automatic overhang detection.
$diff = diff(
[ map $_->p, @{$layerm->slices} ],
- offset([ map @$_, @{$lower_layer->slices} ], +$fw*2),
+ offset([ map @$_, @{$lower_layer->slices} ],
+ #FIXME Vojtech: Why 2x extrusion width? Isn't this too much? Should it not be /2?
+ +$fw/2),
);
# collapse very tiny spots
@@ -288,8 +296,13 @@ sub contact_area {
}
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
$diff = diff(
- offset($diff, $_),
- $slices_margin,
+ offset(
+ $diff,
+ $_,
+ CLIPPER_OFFSET_SCALE,
+ JT_ROUND,
+ scale(0.05)*CLIPPER_OFFSET_SCALE),
+ $slices_margin
);
}
}
@@ -308,7 +321,9 @@ sub contact_area {
my $contact_z = $layer->print_z - $self->contact_distance($layer->height, $nozzle_diameter);
- # ignore this contact area if it's too low
+ # Ignore this contact area if it's too low.
+ #FIXME Better to control the thickness of the interface layer printed, but that would
+ # require having attributes (extrusion width / height, bridge flow etc) per island.
next if $contact_z < $self->object_config->get_value('first_layer_height') - epsilon;
$contact{$contact_z} = [ @contact ];
@@ -336,6 +351,7 @@ sub object_top {
my %top = (); # print_z => [ expolygons ]
return \%top if ($self->object_config->support_material_buildplate_only);
+ # Sum of unsupported contact areas above the current $layer->print_z.
my $projection = [];
foreach my $layer (reverse @{$object->layers}) {
if (my @top = map @{$_->slices->filter_by_type(S_TYPE_TOP)}, @{$layer->regions}) {
@@ -348,7 +364,8 @@ sub object_top {
# having the same Z of top layers
push @$projection, map @{$contact->{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %$contact;
- # now find whether any projection falls onto this top surface
+ # Now find whether any projection of the contact surfaces above $layer->print_z not yet supported by any top surfaces above $layer->z falls onto this top surface.
+ # $touching are the contact surfaces supported exclusively by this @top surfaaces.
my $touching = intersection($projection, [ map $_->p, @top ]);
if (@$touching) {
# grow top surfaces so that interface and support generation are generated
@@ -382,7 +399,10 @@ sub support_layers_z {
# initialize known, fixed, support layers
my @z = sort { $a <=> $b }
@$contact_z,
- @$top_z, # TODO: why we have this?
+ # TODO: why we have this?
+ # Vojtech: To detect the bottom interface layers by finding a Z value in the $top_z.
+ @$top_z,
+ # Top surfaces of the bottom interface layers.
(map $_ + $contact_distance, @$top_z);
# enforce first layer height
@@ -407,10 +427,15 @@ sub support_layers_z {
for (my $i = $#z; $i >= $self->object_config->raft_layers; $i--) {
my $target_height = $support_material_height;
if ($i > 0 && $top{ $z[$i-1] }) {
+ # Bridge flow?
+ #FIXME We want to enforce not only the bridge flow height, but also the interface gap!
+ # This will introduce an additional layer if the gap is set to an extreme value!
$target_height = $nozzle_diameter;
}
# enforce first layer height
+ #FIXME better to split the layers regularly, than to bite a constant height one at a time,
+ # and then be left with a very thin layer at the end.
if (($i == 0 && $z[$i] > $target_height + $first_layer_height)
|| ($z[$i] - $z[$i-1] > $target_height + Slic3r::Geometry::epsilon)) {
splice @z, $i, 0, ($z[$i] - $target_height);
@@ -427,8 +452,11 @@ sub support_layers_z {
return \@z;
}
-sub generate_interface_layers {
+sub generate_top_interface_layers {
my ($self, $support_z, $contact, $top) = @_;
+
+ # If no interface layers are allowed, don't generate top interface layers.
+ return if $self->object_config->support_material_interface_layers == 0;
# let's now generate interface layers below contact areas
my %interface = (); # layer_id => [ polygons ]
@@ -519,6 +547,7 @@ sub generate_base_layers {
# let's now generate support layers under interface layers
my $base = {}; # layer_id => [ polygons ]
{
+ my $fillet_radius_scaled = scale($self->object_config->support_material_spacing);
for my $i (reverse 0 .. $#$support_z-1) {
my $z = $support_z->[$i];
my @overlapping_layers = $self->overlapping_layers($i, $support_z);
@@ -531,19 +560,36 @@ sub generate_base_layers {
@upper_contact = @{ $contact->{$support_z->[$i+1]} || [] };
}
+ my $trim_polygons = [
+ (map @$_, map $top->{$_}, grep exists $top->{$_}, @overlapping_z), # top slices on this layer
+ (map @$_, map $interface->{$_}, grep exists $interface->{$_}, @overlapping_layers), # interface regions on this layer
+ (map @$_, map $contact->{$_}, grep exists $contact->{$_}, @overlapping_z), # contact regions on this layer
+ ];
+
$base->{$i} = diff(
[
@{ $base->{$i+1} || [] }, # support regions on upper layer
@{ $interface->{$i+1} || [] }, # interface regions on upper layer
@upper_contact, # contact regions on upper layer
],
- [
- (map @$_, map $top->{$_}, grep exists $top->{$_}, @overlapping_z), # top slices on this layer
- (map @$_, map $interface->{$_}, grep exists $interface->{$_}, @overlapping_layers), # interface regions on this layer
- (map @$_, map $contact->{$_}, grep exists $contact->{$_}, @overlapping_z), # contact regions on this layer
- ],
- 1,
+ $trim_polygons,
+ 1, # safety offset to merge the touching source polygons
);
+
+ if (0) {
+ # Fillet the base polygons and trim them again with the top, interface and contact layers.
+ $base->{$i} = diff(
+ offset2(
+ $base->{$i},
+ $fillet_radius_scaled,
+ -$fillet_radius_scaled,
+ # Use a geometric offsetting for filleting.
+ CLIPPER_OFFSET_SCALE,
+ JT_ROUND,
+ 0.2*$fillet_radius_scaled*CLIPPER_OFFSET_SCALE),
+ $trim_polygons,
+ 0); # don't apply the safety offset.
+ }
}
}
@@ -602,8 +648,8 @@ sub generate_toolpaths {
}
my %fillers = (
- interface => $object->fill_maker->filler('rectilinear'),
- support => $object->fill_maker->filler($pattern),
+ interface => $object->fill_maker2->filler('rectilinear'),
+ support => $object->fill_maker2->filler($pattern),
);
my $interface_angle = $self->object_config->support_material_angle + 90;
@@ -635,7 +681,8 @@ sub generate_toolpaths {
if (0) {
require "Slic3r/SVG.pm";
- Slic3r::SVG::output("layer_" . $z . ".svg",
+ Slic3r::SVG::output("out\\layer_" . $z . ".svg",
+ blue_expolygons => union_ex($base),
red_expolygons => union_ex($contact),
green_expolygons => union_ex($interface),
);
@@ -718,8 +765,8 @@ sub generate_toolpaths {
# interface and contact infill
if (@$interface || @$contact_infill) {
- $fillers{interface}->angle($interface_angle);
- $fillers{interface}->spacing($_interface_flow->spacing);
+ $fillers{interface}->set_angle($interface_angle);
+ $fillers{interface}->set_spacing($_interface_flow->spacing);
# find centerline of the external loop
$interface = offset2($interface, +scaled_epsilon, -(scaled_epsilon + $_interface_flow->scaled_width/2));
@@ -745,7 +792,7 @@ sub generate_toolpaths {
my @paths = ();
foreach my $expolygon (@{union_ex($interface)}) {
- my @p = $fillers{interface}->fill_surface(
+ my $polylines = $fillers{interface}->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
density => $interface_density,
layer_height => $layer->height,
@@ -759,8 +806,8 @@ sub generate_toolpaths {
mm3_per_mm => $mm3_per_mm,
width => $_interface_flow->width,
height => $layer->height,
- ), @p;
- }
+ ), @$polylines,
+ }
$layer->support_interface_fills->append(@paths);
}
@@ -768,30 +815,39 @@ sub generate_toolpaths {
# support or flange
if (@$base) {
my $filler = $fillers{support};
- $filler->angle($angles[ ($layer_id) % @angles ]);
+ $filler->set_angle($angles[ ($layer_id) % @angles ]);
# We don't use $base_flow->spacing because we need a constant spacing
# value that guarantees that all layers are correctly aligned.
- $filler->spacing($flow->spacing);
+ $filler->set_spacing($flow->spacing);
my $density = $support_density;
my $base_flow = $_flow;
# find centerline of the external loop/extrusions
my $to_infill = offset2_ex($base, +scaled_epsilon, -(scaled_epsilon + $_flow->scaled_width/2));
+
+ if (0) {
+ require "Slic3r/SVG.pm";
+ Slic3r::SVG::output("out\\to_infill_base" . $z . ".svg",
+ red_expolygons => union_ex($contact),
+ green_expolygons => union_ex($interface),
+ blue_expolygons => $to_infill,
+ );
+ }
my @paths = ();
# base flange
if ($layer_id == 0) {
$filler = $fillers{interface};
- $filler->angle($self->object_config->support_material_angle + 90);
+ $filler->set_angle($self->object_config->support_material_angle + 90);
$density = 0.5;
$base_flow = $self->first_layer_flow;
# use the proper spacing for first layer as we don't need to align
# its pattern to the other layers
- $filler->spacing($base_flow->spacing);
+ $filler->set_spacing($base_flow->spacing);
} elsif ($with_sheath) {
# draw a perimeter all around support infill
# TODO: use brim ordering algorithm
@@ -808,9 +864,8 @@ sub generate_toolpaths {
$to_infill = offset_ex([ map @$_, @$to_infill ], -$_flow->scaled_spacing);
}
- my $mm3_per_mm = $base_flow->mm3_per_mm;
foreach my $expolygon (@$to_infill) {
- my @p = $filler->fill_surface(
+ my $polylines = $filler->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
density => $density,
layer_height => $layer->height,
@@ -820,10 +875,10 @@ sub generate_toolpaths {
push @paths, map Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_SUPPORTMATERIAL,
- mm3_per_mm => $mm3_per_mm,
+ mm3_per_mm => $base_flow->mm3_per_mm,
width => $base_flow->width,
height => $layer->height,
- ), @p;
+ ), @$polylines;
}
$layer->support_fills->append(@paths);
@@ -864,8 +919,11 @@ sub generate_pillars_shape {
my $pillar_size = scale PILLAR_SIZE;
my $pillar_spacing = scale PILLAR_SPACING;
+ # A regular grid of pillars, filling the 2D bounding box.
+ # arrayref of polygons
my $grid; # arrayref of polygons
{
+ # Rectangle with a side of 2.5x2.5mm.
my $pillar = Slic3r::Polygon->new(
[0,0],
[$pillar_size, 0],
@@ -873,7 +931,9 @@ sub generate_pillars_shape {
[0, $pillar_size],
);
+ # A regular grid of pillars, filling the 2D bounding box.
my @pillars = ();
+ # 2D bounding box of the projection of all contact polygons.
my $bb = Slic3r::Geometry::BoundingBox->new_from_points([ map @$_, map @$_, values %$contact ]);
for (my $x = $bb->x_min; $x <= $bb->x_max-$pillar_size; $x += $pillar_spacing) {
for (my $y = $bb->y_min; $y <= $bb->y_max-$pillar_size; $y += $pillar_spacing) {
@@ -962,7 +1022,7 @@ sub overlapping_layers {
sub contact_distance {
my ($self, $layer_height, $nozzle_diameter) = @_;
-
+
my $extra = $self->object_config->support_material_contact_distance;
if ($extra == 0) {
return $layer_height;