From 7d7f093120df5fcdfd1f9b21fc6b0622636a7ff1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 16 Oct 2016 16:30:56 +0200 Subject: [PATCH] C++ supports sketched, but not finalized yet. Slic3r is still using the old Perl supports, but this time with the C++ fillers. --- lib/Slic3r.pm | 1 + lib/Slic3r/Print/GCode.pm | 2 + lib/Slic3r/Print/Object.pm | 36 +- lib/Slic3r/Print/SupportMaterial.pm | 124 ++-- xs/MANIFEST | 1 + xs/lib/Slic3r/XS.pm | 16 + xs/src/libslic3r/Fill/FillBase.cpp | 14 +- xs/src/libslic3r/Fill/FillBase.hpp | 2 + xs/src/libslic3r/Flow.cpp | 9 +- xs/src/libslic3r/Layer.hpp | 3 +- xs/src/libslic3r/LayerRegion.cpp | 6 - xs/src/libslic3r/Print.hpp | 4 +- xs/src/libslic3r/PrintObject.cpp | 6 - xs/src/libslic3r/SupportMaterial.cpp | 815 ++++++++++++--------------- xs/src/libslic3r/SupportMaterial.hpp | 93 +-- xs/src/perlglue.cpp | 1 + xs/xsp/SupportMaterial.xsp | 18 +- xs/xsp/my.map | 4 + xs/xsp/typemap.xspt | 4 + 19 files changed, 602 insertions(+), 557 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; diff --git a/xs/MANIFEST b/xs/MANIFEST index 4594a074a..5a0a3e420 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -88,6 +88,7 @@ src/libslic3r/PrintConfig.cpp src/libslic3r/PrintConfig.hpp src/libslic3r/PrintObject.cpp src/libslic3r/PrintRegion.cpp +src/libslic3r/SupportMaterial.cpp src/libslic3r/SupportMaterial.hpp src/libslic3r/Surface.cpp src/libslic3r/Surface.hpp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 8fb933181..9b7cfcddf 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -229,6 +229,21 @@ sub new { return $self; } +package Slic3r::Print::SupportMaterial2; + +sub new { + my ($class, %args) = @_; + + return $class->_new( + $args{print_config}, # required + $args{object_config}, # required + $args{first_layer_flow}, # required + $args{flow}, # required + $args{interface_flow}, # required + $args{soluble_interface} // 0 + ); +} + package Slic3r::GUI::_3DScene::GLVertexArray; sub CLONE_SKIP { 1 } @@ -283,6 +298,7 @@ for my $class (qw( Slic3r::Print::State Slic3r::Surface Slic3r::Surface::Collection + Slic3r::Print::SupportMaterial2 Slic3r::TriangleMesh )) { diff --git a/xs/src/libslic3r/Fill/FillBase.cpp b/xs/src/libslic3r/Fill/FillBase.cpp index 3c652fe85..42c1f5ab2 100644 --- a/xs/src/libslic3r/Fill/FillBase.cpp +++ b/xs/src/libslic3r/Fill/FillBase.cpp @@ -14,13 +14,6 @@ namespace Slic3r { -Fill* Fill::new_from_type(const std::string &type) -{ - static t_config_enum_values enum_keys_map = ConfigOptionEnum::get_enum_values(); - t_config_enum_values::const_iterator it = enum_keys_map.find(type); - return (it == enum_keys_map.end()) ? NULL : new_from_type(InfillPattern(it->second)); -} - Fill* Fill::new_from_type(const InfillPattern type) { switch (type) { @@ -39,6 +32,13 @@ Fill* Fill::new_from_type(const InfillPattern type) } } +Fill* Fill::new_from_type(const std::string &type) +{ + static t_config_enum_values enum_keys_map = ConfigOptionEnum::get_enum_values(); + t_config_enum_values::const_iterator it = enum_keys_map.find(type); + return (it == enum_keys_map.end()) ? NULL : new_from_type(InfillPattern(it->second)); +} + Polylines Fill::fill_surface(const Surface *surface, const FillParams ¶ms) { // Perform offset. diff --git a/xs/src/libslic3r/Fill/FillBase.hpp b/xs/src/libslic3r/Fill/FillBase.hpp index f4c55cbc0..c3ee734b3 100644 --- a/xs/src/libslic3r/Fill/FillBase.hpp +++ b/xs/src/libslic3r/Fill/FillBase.hpp @@ -7,6 +7,7 @@ #include "../libslic3r.h" #include "../BoundingBox.hpp" +#include "../PrintConfig.hpp" namespace Slic3r { @@ -52,6 +53,7 @@ public: public: virtual ~Fill() {} + static Fill* Fill::new_from_type(const InfillPattern type); static Fill* new_from_type(const std::string &type); void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; } diff --git a/xs/src/libslic3r/Flow.cpp b/xs/src/libslic3r/Flow.cpp index 6b3d1986c..49a55a50e 100644 --- a/xs/src/libslic3r/Flow.cpp +++ b/xs/src/libslic3r/Flow.cpp @@ -77,10 +77,11 @@ Flow::mm3_per_mm() const { } /* This static method returns bridge width for a given nozzle diameter. */ -float -Flow::_bridge_width(float nozzle_diameter, float bridge_flow_ratio) { - if (bridge_flow_ratio == 1) return nozzle_diameter; // optimization to avoid sqrt() - return sqrt(bridge_flow_ratio * (nozzle_diameter*nozzle_diameter)); +float Flow::_bridge_width(float nozzle_diameter, float bridge_flow_ratio) { + return (bridge_flow_ratio == 1.) ? + // optimization to avoid sqrt() + nozzle_diameter : + sqrt(bridge_flow_ratio) * nozzle_diameter; } /* This static method returns a sane extrusion width default. */ diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index 098797d8f..523674681 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -26,7 +26,8 @@ class LayerRegion public: Layer* layer(); - PrintRegion* region(); + PrintRegion* region() { return this->_region; } + const PrintRegion* region() const { return this->_region; } // collection of surfaces generated by slicing the original geometry // divided by type top/bottom/internal diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 64482145e..dcea83bd4 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -28,12 +28,6 @@ LayerRegion::layer() return this->_layer; } -PrintRegion* -LayerRegion::region() -{ - return this->_region; -} - Flow LayerRegion::flow(FlowRole role, bool bridge, double width) const { diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 755b39e9d..1ad20afa5 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -120,7 +120,9 @@ public: size_t total_layer_count() const; size_t layer_count() const; void clear_layers(); - Layer* get_layer(int idx); + Layer* get_layer(int idx) { return this->layers.at(idx); } + const Layer* get_layer(int idx) const { return this->layers.at(idx); } + // print_z: top of the layer; slice_z: center of the layer. Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z); void delete_layer(int idx); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 97022a414..ac477f4d7 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -149,12 +149,6 @@ PrintObject::clear_layers() this->delete_layer(i); } -Layer* -PrintObject::get_layer(int idx) -{ - return this->layers.at(idx); -} - Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z) { diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 39245605e..5d4d0f34c 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -1,28 +1,48 @@ -#include "PerimeterGenerator.hpp" #include "ClipperUtils.hpp" #include "ExtrusionEntityCollection.hpp" +#include "PerimeterGenerator.hpp" +#include "Print.hpp" +#include "Layer.hpp" +#include "SupportMaterial.hpp" +#include "Fill/FillBase.hpp" + #include #include namespace Slic3r { -// increment used to reach MARGIN in steps to avoid trespassing thin objects -#define MARGIN_STEPS 3 -// generate a tree-like structure to save material +// Increment used to reach MARGIN in steps to avoid trespassing thin objects +#define NUM_MARGIN_STEPS 3 + +// Dimensions of a tree-like structure to save material #define PILLAR_SIZE (2.5) #define PILLAR_SPACING 10 -inline Layer& layer_allocate(std::deque &layer_storage) +// Using the std::deque as an allocator. +inline PrintSupportMaterial::MyLayer& layer_allocate( + std::deque &layer_storage, + PrintSupportMaterial::SupporLayerType layer_type) { - m_layer_storage.push_back(Layer()); - return m_layer.back(); + layer_storage.push_back(PrintSupportMaterial::MyLayer()); + layer_storage.back().layer_type = layer_type; + return layer_storage.back(); } -void PrintSupportMaterial::generate(PrintObject *object) +inline void layers_append(PrintSupportMaterial::MyLayersPtr &dst, const PrintSupportMaterial::MyLayersPtr &src) +{ + dst.insert(dst.end(), src.begin(), src.end()); +} + +inline void polygons_append(Polygons &dst, const Polygons &src) +{ + dst.insert(dst.end(), src.begin(), src.end()); +} + +void PrintSupportMaterial::generate(PrintObject &object) { coordf_t max_object_layer_height = 0.; - for (size_t i = 0; i < object->layer_count(); ++ i) - max_object_layer_height = std::max(max_object_layer_height, object->get_layer(i)->height); + for (size_t i = 0; i < object.layer_count(); ++ i) + max_object_layer_height = std::max(max_object_layer_height, object.get_layer(i)->height); if (m_support_layer_height_max == 0) m_support_layer_height_max = std::max(max_object_layer_height, 0.75 * m_flow.nozzle_diameter); @@ -30,64 +50,85 @@ void PrintSupportMaterial::generate(PrintObject *object) m_support_interface_layer_height_max = std::max(max_object_layer_height, 0.75 * m_interface_flow.nozzle_diameter); // Layer instances will be allocated by std::deque and they will be kept until the end of this function call. - // The layers will be referenced by various LayersPtr (std::vector) - std::deque layer_storage; + // The layers will be referenced by various LayersPtr (of type std::vector) + MyLayerStorage layer_storage; - // Determine the top surfaces of the support, defined as: + // Determine the top contact surfaces of the support, defined as: // contact = overhangs - clearance + margin // This method is responsible for identifying what contact surfaces // should the support material expose to the object in order to guarantee // that it will be effective, regardless of how it's built below. - LayersSet top_contacts = this->top_contact_layers(object, layer_storage); + MyLayersPtr top_contacts = this->top_contact_layers(object, layer_storage); if (top_contacts.empty()) + // Nothing is supported, no supports are generated. return; - // Determine the top surfaces of the object. We need these to determine - // the layer heights of support material and to clip support to the object - // silhouette. - LayersSet bottom_contacts = this->bottom_contact_layers(object, top_contacts, layer_storage); + // Determine the bottom contact surfaces of the supports over the top surfaces of the object. + // Depending on whether the support is soluble or not, the contact layer thickness is decided. + MyLayersPtr bottom_contacts = this->bottom_contact_layers(object, top_contacts, layer_storage); + // Because the top and bottom contacts are thick slabs, they may overlap causing over extrusion + // and unwanted strong bonds to the object. + // Rather trim the top contacts by their overlapping bottom contacts to leave a gap instead of over extruding. this->trim_top_contacts_by_bottom_contacts(object, bottom_contacts, top_contacts); - // We now know the upper and lower boundaries for our support material object - // (@$contact_z and @$top_z), so we can generate intermediate layers. - LayersSet support_layers = this->support_layers(object, bottom_contacts, top_contacts, layer_storage, max_object_layer_height); + // Generate intermediate layers between the top / bottom support contact layers, + // trimmed by the object. + // The layers may or may not be synchronized with the object layers, depending on the configuration. + // For example, a single nozzle multi material printing will need to generate a waste tower, which in turn + // wastes less material, if there are as little layers as possible, therefore minimizing the material swaps. + MyLayersPtr intermediate_layers = this->raft_and_intermediate_support_layers( + object, bottom_contacts, top_contacts, layer_storage, max_object_layer_height); +/* // If we wanted to apply some special logic to the first support layers lying on // object's top surfaces this is the place to detect them LayersSet shape; - if (this->object_config->support_material_pattern.value == smpPillars) + if (m_objectconfig->support_material_pattern.value == smpPillars) shape = this->generate_pillars_shape(contact, support_z); +*/ - // Propagate contact layers downwards to generate interface layers - LayersSet interface = this->generate_top_interface_layers(support_z, contact, top); - this->clip_with_object(interface, support_z, object); - if (! shape.empty()) + // Propagate top / bottom contact layers to generate interface layers. + MyLayersPtr interface_layers = this->generate_interface_layers( + object, bottom_contacts, top_contacts, intermediate_layers, layer_storage); + +/* + // Clip with the pillars. + if (! shape.empty()) { this->clip_with_shape(interface, shape); - - // Propagate contact layers and interface layers downwards to generate - // the main support layers. - LayersSet base = this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers, layer_storage); - if (! shape.empty()) this->clip_with_shape(base, shape); + } +*/ - // Install support layers into object. - for (size_t i = 0; i < support_z.size(); ++ i) { - object->add_support_layer( - i, // id - (i == 0) ? support_z[i] : (support_z[i] - support_z[i-1]), // height - support_z[i] // print_z - ); - if (i > 0) { - SupportLayer *sl1 = object->get_support_layer[object->support_layer_count()-2]; - SupportLayer *sl2 = object->get_support_layer[object->support_layer_count()-1]; - sl1->set_upper_layer(sl2); - sl2->set_lower_layer(sl1); + // Install support layers into the object. + MyLayersPtr layers_sorted; + layers_sorted.reserve(bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size()); + layers_append(layers_sorted, bottom_contacts); + layers_append(layers_sorted, top_contacts); + layers_append(layers_sorted, intermediate_layers); + layers_append(layers_sorted, interface_layers); + std::sort(layers_sorted.begin(), layers_sorted.end()); + + int layer_id = 0; + for (int i = 0; i < int(layers_sorted.size());) { + // Find the last layer with the same print_z, find the minimum layer height of all. + int j = i + 1; + coordf_t height_min = layers_sorted[i]->height; + for (; j < layers_sorted.size() && layers_sorted[i]->print_z == layers_sorted[j]->print_z; ++ j) + height_min = std::min(height_min, layers_sorted[j]->height); + object.add_support_layer(layer_id, height_min, layers_sorted[i]->print_z); + if (layer_id > 0) { + SupportLayer *sl1 = object.support_layers[object.support_layer_count()-2]; + SupportLayer *sl2 = object.support_layers.back(); + sl1->upper_layer = sl2; + sl2->lower_layer = sl1; } + i = j; + ++ layer_id; } // Generate the actual toolpaths and save them into each layer. - this->generate_toolpaths(object, overhang, contact, interface, base); + this->generate_toolpaths(object, bottom_contacts, top_contacts, intermediate_layers, interface_layers); } void collect_region_slices_by_type(const Layer &layer, SurfaceType surface_type, Polygons &out) @@ -122,38 +163,7 @@ void collect_region_slices_by_type(const Layer &layer, SurfaceType surface_type, Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_type) { Polygons out; - collect_regon_slices_by_type(layer, surface_type, out); - return out; -} - -void collect_region_slices_all(const Layer &layer, Polygons &out) -{ - // 1) Count the new polygons first. - size_t n_polygons_new = 0; - for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { - const LayerRegion ®ion = *(*it_region); - const SurfaceCollection &slices = region.slices; - for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) - n_polygons_new += it->expolygon.holes.size() + 1; - } - - // 2) Collect the new polygons. - out.reserve(out.size() + n_polygons_new); - for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { - const LayerRegion ®ion = *(*it_region); - const SurfaceCollection &slices = region.slices; - for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { - const Surface &surface = *it; - out.push_back(surface.expolygon.contour); - out.insert(out.end(), surface.expolygon.holes.begin(), surface.expolygon.holes.end()); - } - } -} - -Polygons collect_region_slices_all(const Layer &layer) -{ - Polygons out; - collect_region_slices_all(layer, out); + collect_region_slices_by_type(layer, surface_type, out); return out; } @@ -184,72 +194,40 @@ Polygons collect_region_slices_outer(const Layer &layer) return out; } -void collect_layer_slices_all(const Layer &layer, Polygons &out) -{ - // 1) Count the new polygons first. - size_t n_polygons_new = 0; - const SurfaceCollection &slices = region.slices; - for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) - n_polygons_new += it->expolygon.holes.size() + 1; - - // 2) Collect the new polygons. - for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { - const Surface &surface = *it; - out.push_back(surface.expolygon.contour); - out.insert(out.end(), surface.expolygon.holes.begin(), surface.expolygon.holes.end()); - } -} - -Polygons collect_layer_slices_all(const Layer &layer) -{ - Polygons out; - collect_layer_slices_all(layer, out); - return out; -} - -PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const PrintObject &object, std::deque &layer_storage) const +// Find the top contact surfaces of the support or the raft. +PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const PrintObject &object, MyLayerStorage &layer_storage) const { // Output layers, sorte by top Z. - LayersPtr contact_out; + MyLayersPtr contact_out; - // if user specified a custom angle threshold, convert it to radians + // If user specified a custom angle threshold, convert it to radians. double threshold_rad = 0.; - if (this->object_config->support_material_threshold > 0) { - threshold_rad = M_PI * double(this->object_config->support_material_threshold + 1) / 180.; // +1 makes the threshold inclusive + if (m_object_config->support_material_threshold > 0) { + threshold_rad = M_PI * double(m_object_config->support_material_threshold + 1) / 180.; // +1 makes the threshold inclusive // Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); } // Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces // and subtract $buildplate_only_top_surfaces from the contact surfaces, so // there is no contact surface supported by a top surface. - bool buildplate_only = this->object_config->support_material && this->object_config->support_material_buildplate_only; + bool buildplate_only = m_object_config->support_material && m_object_config->support_material_buildplate_only; Polygons buildplate_only_top_surfaces; -/* - Layer *first_object_layer = object.get_layer(this->object_config->raft_layers); - if (first_object_layer == NULL) - // Nothing to print, nothing to support. - return contact_out; - - // If printing over raft, make sure the bottom of the contact surfaces are above the raft. - coordf_t raft_top = (this->object_config->raft_layers > 0) ? (first_object_layer->print_z - first_object_layer->height) : 0.; -*/ - - // determine contact areas - for (size_t layer_id = 0; layer_id < object->layer_count(); ++ layer_id) { + // Determine top contact areas. + for (size_t layer_id = 0; layer_id < object.layer_count(); ++ layer_id) { // Note that layer_id < layer->id when raft_layers > 0 as the layer->id incorporates the raft layers. // So layer_id == 0 means first object layer and layer->id == 0 means first print layer if there are no explicit raft layers. if (m_object_config->raft_layers == 0) { if (layer_id == 0) // No raft, 1st object layer cannot be supported by a support contact layer. continue; - } else if (! this->object_config->support_material) { + } else if (! m_object_config->support_material) { // If we are only going to generate raft. Just check the 'overhangs' of the first object layer. if (layer_id > 0) break; } - const Layer &layer = *object->get_layer(layer_id); + const Layer &layer = *object.get_layer(layer_id); if (buildplate_only) { // Collect the top surfaces up to this layer and merge them. @@ -266,86 +244,78 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P } } - // detect overhangs and contact areas needed to support them + // Detect overhangs and contact areas needed to support them. Polygons overhang_polygons; Polygons contact_polygons; if (layer_id == 0) { - // this is the first object layer, so we're here just to get the object - // footprint for the raft - // we only consider contours and discard holes to get a more continuous raft + // This is the first object layer, so we're here just to get the object footprint for the raft. + // We only consider contours and discard holes to get a more continuous raft. overhang_polygons = collect_region_slices_outer(layer); // Extend by SUPPORT_MATERIAL_MARGIN, which is 1.5mm - contact_polygons = offset_(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN)); + contact_polygons = offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN)); } else { - const Layer &lower_layer = *object->get_layer(layer_id-1); + // Generate overhang/contact_polygons for non-raft layers. + const Layer &lower_layer = *object.get_layer(int(layer_id)-1); for (LayerRegionPtrs::const_iterator it_layerm = layer.regions.begin(); it_layerm != layer.regions.end(); ++ it_layerm) { const LayerRegion &layerm = *(*it_layerm); // Extrusion width accounts for the roundings of the extrudates. // It is the maximum widh of the extrudate. - coord_t fw = layerm.flow(FLOW_ROLE_EXTERNAL_PERIMETER).scaled_width; + coord_t fw = layerm.flow(frExternalPerimeter).scaled_width(); + coordf_t lower_layer_offset = + (layer_id < m_object_config->support_material_enforce_layers) ? + // Enforce a full possible support, ignore the overhang angle. + 0 : + (threshold_rad > 0. ? + // Overhang defined by an angle. + scale_(lower_layer.height * cos(threshold_rad) / sin(threshold_rad)) : + // Overhang defined by half the extrusion width. + 0.5 * fw); Polygons diff_polygons; - - // If a threshold angle was specified, use a different logic for detecting overhangs. - if (threshold_rad > 0. - || layer_id < this->object_config->support_material_enforce_layers - || (this->object_config->raft_layers > 0 && layer_id == 0)) { - coordf_t d = (threshold_rad > 0.) - ? scale_(lower_layer.height * cos(threshold_rad) / sin(threshold_rad)) - : 0.; - - // Shrinking the supported layer by layer_height/atan(threshold_rad). - diff_polygons = diff( - offset_((Polygons)layerm.slices, -d), - (Polygons)lower_layer->slices); - - // only enforce spacing from the object ($fw/2) if the threshold angle - // is not too high: in that case, $d will be very small (as we need to catch - // very short overhangs), and such contact area would be eaten by the - // enforced spacing, resulting in high threshold angles to be almost ignored - if (d > 0.5*fw) - diff_polygons = diff( - offset(diff_polygons, d - 0.5*fw), - (Polygons)lower_layer.slices); - } else { - // Automatic overhang detection. + if (lower_layer_offset == 0.) { diff_polygons = diff( (Polygons)layerm.slices, - offset((Polygons)lower_layer.slices, 0.5*fw)); - - // collapse very tiny spots + (Polygons)lower_layer.slices); + } else { + // Get the regions needing a suport. + diff_polygons = diff( + (Polygons)layerm.slices, + offset((Polygons)lower_layer.slices, lower_layer_offset)); + // Collapse very tiny spots. diff_polygons = offset2(diff_polygons, -0.1*fw, +0.1*fw); - - // $diff now contains the ring or stripe comprised between the boundary of - // lower slices and the centerline of the last perimeter in this overhanging layer. - // Void $diff means that there's no upper perimeter whose centerline is - // outside the lower slice boundary, thus no overhang + if (diff_polygons.empty()) + continue; + // Offset the support regions back to a full overhang, restrict them to the full overhang. + diff_polygons = intersection(offset(diff_polygons, lower_layer_offset), (Polygons)layerm.slices); } - - if (this->object_config->dont_support_bridges) { + if (diff_polygons.empty()) + continue; + + if (m_object_config->dont_support_bridges) { // compute the area of bridging perimeters // Note: this is duplicate code from GCode.pm, we need to refactor Polygons bridged_perimeters; { - Flow bridge_flow = layerm.flow(FLOW_ROLE_PERIMETER, true); + Flow bridge_flow = layerm.flow(frPerimeter, true); - coordf_t nozzle_diameter = this->print_config->get_at('nozzle_diameter', layerm.region->config->perimeter_extruder-1); + coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at( + layerm.region()->config.perimeter_extruder-1); Polygons lower_grown_slices = offset((Polygons)lower_layer.slices, +scale_(0.5*nozzle_diameter)); // TODO: split_at_first_point() could split a bridge mid-way Polylines overhang_perimeters; for (size_t i = 0; i < layerm.perimeters.entities.size(); ++ i) { ExtrusionEntity *entity = layerm.perimeters.entities[i]; - ExtrusionLoop *loop = dynamic_cast(entity); + ExtrusionLoop *loop = dynamic_cast(entity); overhang_perimeters.push_back(loop ? - loop->polygon->split_at_first_point() : - dynamic_cast(entity)->path); + loop->as_polyline() : + dynamic_cast(entity)->polyline); } // workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline() for (Polylines::iterator it = overhang_perimeters.begin(); it != overhang_perimeters.end(); ++ it) - (*it)[0].x += 1; - overhang_perimeters = diff(overhang_perimeters, lower_grown_slices); + it->points[0].x += 1; + diff(overhang_perimeters, lower_grown_slices, &overhang_perimeters); // only consider straight overhangs // only consider overhangs having endpoints inside layer's slices @@ -353,17 +323,21 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P // since we're dealing with bridges, we can't assume width is larger than spacing, // so we take the largest value and also apply safety offset to be ensure no gaps // are left in between - coordf_t w = std::max(bridge_flow.scaled_width, bridge_flow.scaled_spacing); + coordf_t w = std::max(bridge_flow.scaled_width(), bridge_flow.scaled_spacing()); for (Polylines::iterator it = overhang_perimeters.begin(); it != overhang_perimeters.end(); ++ it) { if (it->is_straight()) { - it->extend_start($fw); - it->extend_end($fw); - if (layer.slices.contains(it->find_point()) && layer.slices.contains_point(it->last_point())) + it->extend_start(fw); + it->extend_end(fw); + if (layer.slices.contains(it->first_point()) && layer.slices.contains(it->last_point())) { // Offset a polyline into a polygon. - bridged_perimeters.push_back(offset(*it, 0.5 * w + 10.)); + Polylines tmp; tmp.push_back(*it); + Polygons out; + offset(tmp, &out, 0.5 * w + 10.); + polygons_append(bridged_perimeters, out); + } } } - bridged_perimeters = union(bridged_perimeters); + bridged_perimeters = union_(bridged_perimeters); } if (1) { @@ -374,17 +348,27 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P bridges.push_back(it->expolygon.contour); bridges.insert(bridges.end(), it->expolygon.holes.begin(), it->expolygon.holes.end()); } + } bridged_perimeters.insert(bridged_perimeters.end(), bridges.begin(), bridges.end()); diff_polygons = diff(diff_polygons, bridged_perimeters, true); - - Polygons bridge_anchors = intersection(offset(polylines, scale_(SUPPORT_MATERIAL_MARGIN)), bridges); - diff_polygons.insert(diff_polygons.end(), bridge_anchors.begin(), bridge_anchors.end()); + + Polygons unsupported_bridge_polygons; + for (Polylines::const_iterator it = layerm.unsupported_bridge_edges.polylines.begin(); + it != layerm.unsupported_bridge_edges.polylines.end(); ++ it) { + // Offset a polyline into a polygon. + Polylines tmp; tmp.push_back(*it); + Polygons out; + offset(tmp, &out, scale_(SUPPORT_MATERIAL_MARGIN)); + polygons_append(unsupported_bridge_polygons, out); + } + Polygons bridge_anchors = intersection(unsupported_bridge_polygons, bridges); + polygons_append(diff_polygons, bridge_anchors); } else { // just remove bridged areas diff_polygons = diff(diff_polygons, layerm.bridged, true); } - } // if (this->object_config->dont_support_bridges) + } // if (m_objconfig->dont_support_bridges) if (buildplate_only) { // Don't support overhangs above the top surfaces. @@ -394,45 +378,44 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P if (diff_polygons.empty()) continue; - // NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! - //FIXME Vojtech: Is the preceding comment true? - overhang.polygons.insert(overhang.polygons.end(), diff_polygons.begin(), diff_polygons.end()); + + polygons_append(overhang_polygons, diff_polygons); // Let's define the required contact area by using a max gap of half the upper // extrusion width and extending the area according to the configured margin. // We increment the area in steps because we don't want our support to overflow // on the other side of the object (if it's very thin). { - Polygons slices_margin = offset((Polygons)lower_layer.slices, 0.5*fw); + Polygons slices_margin = offset((Polygons)lower_layer.slices, float(0.5*fw)); if (buildplate_only) { // Trim the inflated contact surfaces by the top surfaces as well. - slices_margin.insert(slices_margin.end(), buildplate_only_top_surfaces); + polygons_append(slices_margin, buildplate_only_top_surfaces); slices_margin = union_(slices_margin); } - for (size_t i = 0; i <= MARGIN_STEPS; ++ i) { + for (size_t i = 0; i < NUM_MARGIN_STEPS; ++ i) { diff_polygons = diff( offset( - diff_polygons, - (i == 0) ? (0.5 * fw) : (SUPPORT_MATERIAL_MARGIN / MARGIN_STEPS), + diff_polygons, + SUPPORT_MATERIAL_MARGIN / NUM_MARGIN_STEPS, CLIPPER_OFFSET_SCALE, ClipperLib::jtRound, + // round mitter limit scale_(0.05) * CLIPPER_OFFSET_SCALE), slices_margin); } } - contact.polygons.insert(contact.polygons.end(), diff_polygons.begin(), diff_polygons.end()); - } - } + polygons_append(contact_polygons, diff_polygons); + } // for each layer.region + } // end of Generate overhang/contact_polygons for non-raft layers. // now apply the contact areas to the layer were they need to be made - if (! contact.polygons.empty()) { + if (! contact_polygons.empty()) { // get the average nozzle diameter used on this layer - Layer &new_layer = layer_allocate(layer_storage); - new_layer.layer_type = sltTopContact; + MyLayer &new_layer = layer_allocate(layer_storage, sltTopContact); new_layer.idx_object_layer_above = layer_id; if (m_soluble_interface) { // Align the contact surface height with a layer immediately below the supported layer. - new_layer.print_z = layer.print_z - layer.heigh; + new_layer.print_z = new_layer.print_z - new_layer.height; new_layer.height = (layer_id > 0) ? // Interface layer will be synchronized with the object. object.get_layer(layer_id - 1)->height : @@ -448,14 +431,14 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P coordf_t nozzle_dmr = 0.; size_t n_nozzle_dmrs = 0; for (LayerRegionPtrs::const_iterator it_region_ptr = layer.regions.begin(); it_region_ptr != layer.regions.end(); ++ it_region_ptr) { - const PrintRegion ®ion = (*it_region_ptr)->region; - nozzle_dmr += m_print_config->get_at('nozzle_diameter', region.config->perimeter_extruder-1); - nozzle_dmr += m_print_config->get_at('nozzle_diameter', region.config->infill_extruder-1); - nozzle_dmr += m_print_config->get_at('nozzle_diameter', region.config->solid_infill_extruder-1); + const PrintRegion ®ion = *(*it_region_ptr)->region(); + nozzle_dmr += m_print_config->nozzle_diameter.get_at(region.config.perimeter_extruder-1); + nozzle_dmr += m_print_config->nozzle_diameter.get_at(region.config.infill_extruder-1); + nozzle_dmr += m_print_config->nozzle_diameter.get_at(region.config.solid_infill_extruder-1); n_nozzle_dmrs += 3; } nozzle_dmr /= n_nozzle_dmrs; - new_layer.print_z = layer.print_z - nozzle_dmr - $self->object_config->support_material_contact_distance; + new_layer.print_z = layer.print_z - nozzle_dmr - m_object_config->support_material_contact_distance; // Don't know the height of the top contact layer yet. The top contact layer is printed with a normal flow and // its height will be set adaptively later on. new_layer.height = 0.; @@ -466,13 +449,13 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P // Don't want to print a layer below the first layer height as it may not stick well. //FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact // and it may actually make sense to do it with a thinner layer than the first layer height. - if (new_layer.print_z < this->object_config->get_value('first_layer_height') - EPSILON) + if (new_layer.print_z < m_object_config->first_layer_height + EPSILON) continue; - + new_layer.polygons.swap(contact_polygons); new_layer.aux_polygons = new Polygons(); new_layer.aux_polygons->swap(overhang_polygons); - contact_out.push_back(new_layer); + contact_out.push_back(&new_layer); if (0) { // Slic3r::SVG::output("out\\contact_" . $contact_z . ".svg", @@ -487,25 +470,15 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::top_contact_layers(const P return contact_out; } -/* -static inline LayersPtr sort_layers(LayersSet &layers) -{ - LayersPtr sorted; - for (LayersSet::const_iterator it = layers.begin(); it != layers.end(); ++ it) - sorted.push_back(const_cast(&(*it))); - std::sort(sorted.begin(), sorted.end()); - return sorted; -} -*/ - -void PrintSupportMaterial::bottom_contact_layers(const PrintObject &object, LayersDeque &top_contacts) const +PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::bottom_contact_layers( + const PrintObject &object, const MyLayersPtr &top_contacts, MyLayerStorage &layer_storage) const { // find object top surfaces // we'll use them to clip our support and detect where does it stick - LayersPtr bottom_contact_layers; - if (! self->object_config->support_material_buildplate_only && ! layers.empty()) + MyLayersPtr bottom_contacts; + if (! m_object_config->support_material_buildplate_only && ! top_contacts.empty()) { - // Sum of unsupported contact areas above the current $layer->print_z. + // Sum of unsupported contact areas above the current layer.print_z. Polygons projection; // Last top contact layer visited when collecting the projection of contact areas. int contact_idx = int(top_contacts.size()) - 1; @@ -514,61 +487,58 @@ void PrintSupportMaterial::bottom_contact_layers(const PrintObject &object, Laye Polygons top = collect_region_slices_by_type(layer, stTop); if (top.empty()) continue; - // compute projection of the contact areas above this top layer - // first add all the 'new' contact areas to the current projection - // ('new' means all the areas that are lower than the last top layer - // we considered) - // use <= instead of just < because otherwise we'd ignore any contact regions - // having the same Z of top layers - while (contact_idx >= 0 && top_contacts[contact_idx]->print_z > layer.print_z) { - projection.insert(projection.back(), top_contacts[contact_idx]->polygons.begin(), top_contacts[contact_idx]->polygons.end()); - // 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. + // Collect projections of all contact areas above or at the same level as this top surface. + for (; contact_idx >= 0 && top_contacts[contact_idx]->print_z >= layer.print_z; -- contact_idx) + polygons_append(projection, top_contacts[contact_idx]->polygons); + // Now find whether any projection of the contact surfaces above layer.print_z not yet supported by any + // top surfaces above layer.print_z falls onto this top surface. + // touching are the contact surfaces supported exclusively by this top surfaaces. Polygons touching = intersection(projection, top); if (touching.empty()) continue; // Allocate a new bottom contact layer. - Layer &layer_new = layer_allocate(top_contacts); - bottom_contact_layers.push_back(&layer_new); - layer_new.layer_type = sltBottomContact; - // grow top surfaces so that interface and support generation are generated + MyLayer &layer_new = layer_allocate(layer_storage, sltBottomContact); + bottom_contacts.push_back(&layer_new); + // Grow top surfaces so that interface and support generation are generated // with some spacing from object - it looks we don't need the actual // top shapes so this can be done here - support_layer.height = m_soluble_interface ? + layer_new.height = m_soluble_interface ? // Align the interface layer with the object's layer height. - object->get_layer(layer_id + 1)->height : + object.get_layer(layer_id + 1)->height : // Place a bridge flow interface layer over the top surface. - m_interface_flow->nozzle_diameter; - layer_new.print_z = layer.print_z + support_layer.height + m_object_config->support_material_contact_distance; - new_layer.bottom_z = layer.print_z; + m_interface_flow.nozzle_diameter; + layer_new.print_z = layer.print_z + layer_new.height + + (m_soluble_interface ? 0 : m_object_config->support_material_contact_distance); + layer_new.bottom_z = layer.print_z; layer_new.idx_object_layer_below = layer_id; - layer_new.bridging = true; - Polygons poly_new = offset(touching, m_flow.scaled_width); + layer_new.bridging = ! m_soluble_interface; + Polygons poly_new = offset(touching, float(m_flow.scaled_width())); layer_new.polygons.swap(poly_new); // Remove the areas that touched from the projection that will continue on next, lower, top surfaces. projection = diff(projection, touching); } } - return bottom_contact_layers; + return bottom_contacts; } // Trim the top_contacts layers with the bottom_contacts layers if they overlap, so there would not be enough vertical space for both of them. -void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts(const PrintObject &object, const LayersPtr &bottom_contacts, const LayersPtr &top_contacts) +void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts( + const PrintObject &object, const MyLayersPtr &bottom_contacts, MyLayersPtr &top_contacts) const { size_t idx_top_first = 0; coordf_t min_layer_height = 0.05; // For all bottom contact layers: for (size_t idx_bottom = 0; idx_bottom < bottom_contacts.size() && idx_top_first < top_contacts.size(); ++ idx_bottom) { - const Layer &layer_bottom = *bottom_contacts[idx_bottom]; + const MyLayer &layer_bottom = *bottom_contacts[idx_bottom]; // Find the first top layer overlapping with layer_bottom. - while (idx_top_first < top_contacts.size() && top_contacts[idx_top]->print_z <= layer_bottom.bottom_z) + while (idx_top_first < top_contacts.size() && top_contacts[idx_top_first]->print_z <= layer_bottom.print_z - layer_bottom.height) ++ idx_top_first; // For all top contact layers overlapping with the thick bottom contact layer: for (size_t idx_top = idx_top_first; idx_top < top_contacts.size(); ++ idx_top) { - Layer &layer_top = *top_contacts[idx_top]; + MyLayer &layer_top = *top_contacts[idx_top]; coordf_t interface_z = m_soluble_interface ? (layer_top.bottom_z + EPSILON) : - (layer_top.bottom - min_layer_height); + (layer_top.bottom_z - min_layer_height); if (interface_z < layer_bottom.print_z) { // Layers overlap. Trim layer_top with layer_bottom. layer_top.polygons = diff(layer_top.polygons, layer_bottom.polygons); @@ -578,85 +548,13 @@ void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts(const PrintObjec } } -PrintSupportMaterial::LayersPtr PrintSupportMaterial::raft_and_intermediate_support_layers( +PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::raft_and_intermediate_support_layers( const PrintObject &object, - const LayersPtr &bottom_contacts, - const LayersPtr &top_contacts, - std::deque &layer_storage, - const coordf_t max_object_layer_height); + const MyLayersPtr &bottom_contacts, + const MyLayersPtr &top_contacts, + MyLayerStorage &layer_storage, + const coordf_t max_object_layer_height) const { - // determine layer height for any non-contact layer - // we use max() to prevent many ultra-thin layers to be inserted in case - // layer_height > nozzle_diameter * 0.75 - - //my $nozzle_diameter = $self->print_config->get_at('nozzle_diameter', $self->object_config->support_material_extruder-1); - //my $support_material_height = max($max_object_layer_height, $nozzle_diameter * 0.75); - //my $contact_distance = $self->contact_distance($support_material_height, $nozzle_diameter); - - // Collect all known layers here: - // bottom interface layers, newly created intermediate layers, top interface layers, raft layers. - LayersPtr support_layers; - - coordf_t first_layer_height = m_object_config->get_value('first_layer_height'); - - if (m_object_config->raft_layers == 0) { - // No raft. - } else if (m_object_config->raft_layers == 1) { - // Only the raft interface layer. - } else { - assert(m_object_config->raft_layers > 1); - // Generate the - } - while (z.front()->print_z < first_layer_height - EPSILON) - z.erase(z.begin()); - if (z.empty()) - return z; - - if (z.front()->print_z > first_layer_height + EPSILON) { - Layer support_layer; - support_layer.layer_type = stlFirstLayer; - support_layer.print_z = first_layer_height; - support_layer.height = first_layer_height; - LayersSet::const_iterator it = other.insert(support_layer); - z.insert(z.begin(), support_layer); - } - - // Add raft layers by dividing the space between first layer and first contact layer evenly. - if (m_object_config->raft_layers > 1 && z.size() > 1) { - // z[1] is last raft layer (contact layer for the first layer object) - coordf_t height = (z[1].print_z - z[0].print_z) / (m_object_config->raft_layers - 1); - // Since we already have two raft layers ($z[0] and $z[1]) we need to insert raft_layers-2 more. - z.insert(z.begin() + 1, m_object_config - 2, NULL); - for (size_t i = 1; i < m_object_config->raft_layers; ++ i) { - Layer support_layer; - support_layer.layer_type = stlRaft; - support_layer.print_z = z.front()->print_z + height * i; - support_layer.height = height; - LayersSet::const_iterator it = other.insert(support_layer); - z.insert(z.begin(), support_layer); - } - } - - // create other layers (skip raft layers as they're already done and use thicker layers) - for (int i = int(z.size()); i >= m_object_config->raft_layers; -- i) { - coordf_t 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 + EPSILON)) { - splice @z, $i, 0, ($z[$i] - $target_height); - $i++; - } - } - // Collect and sort the extremes (bottoms of the top contacts and tops of the bottom contacts). std::vector extremes; extremes.reserve(top_contacts.size() + bottom_contacts.size()); @@ -667,94 +565,95 @@ PrintSupportMaterial::LayersPtr PrintSupportMaterial::raft_and_intermediate_supp std::sort(extremes.begin(), extremes.end()); // Generate intermediate layers. - LayersPtr intermediate_layers; - coordf_t max_support_layer_height; + MyLayersPtr intermediate_layers; for (size_t idx_extreme = 0; idx_extreme + 1 < extremes.size(); ++ idx_extreme) { LayerExtreme &extr1 = extremes[idx_extreme]; LayerExtreme &extr2 = extremes[idx_extreme+1]; coordf_t dist = extr2.z() - extr1.z(); assert(dist > 0.); // Insert intermediate layers. - size_t n_layers_extra = size_t(ceil(dist / max_support_layer_height)); + size_t n_layers_extra = size_t(ceil(dist / m_support_layer_height_max)); coordf_t step = dist / coordf_t(n_layers_extra); - if (! m_soluble_interface && extr2.layer->layer_type == stlTop) { + if (! m_soluble_interface && extr2.layer->layer_type == sltTopContact) { // This is a top interface layer, which does not have a height assigned yet. Do it now. + if (m_synchronize_support_layers_with_object) { + // Find the + } extr2.layer->height = step; - extr2.layer->bottom_z = extr2.layer->top_z - step; + extr2.layer->bottom_z = extr2.layer->print_z - step; -- n_layers_extra; } for (size_t i = 0; i < n_layers_extra; ++ i) { - Layer &layer_new = layer_allocate(layer_storage); - layer_new.layer_type = sltIntermediate; + MyLayer &layer_new = layer_allocate(layer_storage, stlIntermediate); layer_new.height = step; layer_new.bottom_z = extr1.z() + i * step; - layer_new.top_z = layer_new.bottom_z + step; + layer_new.print_z = layer_new.bottom_z + step; intermediate_layers.push_back(&layer_new); } } - return support_layers; -} - -inline void polygons_append(Polygons &dst, const Polygons &src) -{ - dst.insert(dst.end(), src.begin(), src.end()); + return intermediate_layers; } // At this stage there shall be intermediate_layers allocated between bottom_contacts and top_contacts, but they have no polygons assigned. -// Also the bottom/top_contacts shall have a thickness assigned. +// Also the bottom/top_contacts shall have a thickness assigned already. void PrintSupportMaterial::generate_base_layers( const PrintObject &object, - const LayersPtr &bottom_contacts, - const LayersPtr &top_contacts, - LayersPtr &intermediate_layers) + const MyLayersPtr &bottom_contacts, + const MyLayersPtr &top_contacts, + MyLayersPtr &intermediate_layers) const { if (top_contacts.empty()) // No top contacts -> no intermediate layers will be produced. return; // coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing); + //FIXME make configurable: + coordf_t overlap_extra_above = 0.2; + coordf_t overlap_extra_below = 0.2; int idx_top_contact_above = int(top_contacts.size()) - 1; int idx_top_contact_overlapping = int(top_contacts.size()) - 1; int idx_bottom_contact_overlapping = int(bottom_contacts.size()) - 1; for (int idx_intermediate = int(intermediate_layers.size()) - 1; idx_intermediate >= 0; -- idx_intermediate) { - Layer &layer_intermediate = intermediate_layers[idx_intermediate]; + MyLayer &layer_intermediate = *intermediate_layers[idx_intermediate]; // New polygons for layer_intermediate. Polygons polygons_new; // Find a top_contact layer touching the layer_intermediate from above, if any, and collect its polygons into polygons_new. - while (idx_top_contact_above >= 0 && top_contacts[idx_top_contact_above].bottom_z > layer_intermediate.print_z + EPSILON) + while (idx_top_contact_above >= 0 && top_contacts[idx_top_contact_above]->bottom_z > layer_intermediate.print_z + EPSILON) -- idx_top_contact_above; - if (idx_top_contact_above >= 0 && top_contacts[idx_top_contact_above].top_z > layer_intermediate.print_z) - polygons_append(polygons_new, top_contacts[idx_top_contact_above].polygons); + if (idx_top_contact_above >= 0 && top_contacts[idx_top_contact_above]->print_z > layer_intermediate.print_z) + polygons_append(polygons_new, top_contacts[idx_top_contact_above]->polygons); // Add polygons from the intermediate layer above. if (idx_intermediate + 1 < int(intermediate_layers.size())) - polygons_append(polygons_new, intermediate_layers[idx_intermediate+1].polygons); + polygons_append(polygons_new, intermediate_layers[idx_intermediate+1]->polygons); // Polygons to trim polygons_new. Polygons polygons_trimming; // Find the first top_contact layer intersecting with this layer. - while (idx_top_contact_overlapping >= 0 && top_contacts[idx_top_contact_overlapping].bottom_z > layer_intermediate.print_z + overlap_extra_above - EPSILON) + while (idx_top_contact_overlapping >= 0 && + top_contacts[idx_top_contact_overlapping]->bottom_z > layer_intermediate.print_z + overlap_extra_above - EPSILON) -- idx_top_contact_overlapping; // Collect all the top_contact layer intersecting with this layer. for (int i = idx_top_contact_overlapping; i >= 0; -- i) { - Layer &layer_top_overlapping = top_contacts[idx_top_contact_overlapping]; + MyLayer &layer_top_overlapping = *top_contacts[idx_top_contact_overlapping]; if (layer_top_overlapping.print_z < layer_intermediate.bottom_z - overlap_extra_below) break; polygons_append(polygons_trimming, layer_top_overlapping.polygons); } // Find the first bottom_contact layer intersecting with this layer. - while (idx_bottom_contact_overlapping >= 0 && bottom_contacts[idx_bottom_contact_overlapping].bottom_z > layer_intermediate.print_z + overlap_extra_above - EPSILON) + while (idx_bottom_contact_overlapping >= 0 && + bottom_contacts[idx_bottom_contact_overlapping]->bottom_z > layer_intermediate.print_z + overlap_extra_above - EPSILON) -- idx_bottom_contact_overlapping; // Collect all the top_contact layer intersecting with this layer. for (int i = idx_bottom_contact_overlapping; i >= 0; -- i) { - Layer &layer_bottom_overlapping = bottom_contacts[idx_bottom_contact_overlapping]; + MyLayer &layer_bottom_overlapping = *bottom_contacts[idx_bottom_contact_overlapping]; if (layer_bottom_overlapping.print_z < layer_intermediate.print_z - layer_intermediate.height - overlap_extra_below) break; polygons_append(polygons_trimming, layer_bottom_overlapping.polygons); @@ -790,11 +689,11 @@ void PrintSupportMaterial::generate_base_layers( //FIXME This could be parallelized. const coordf_t gap_extra_above = 0.1f; const coordf_t gap_extra_below = 0.1f; - const coordf_t gap_xy_scaled = m_flow.scaled_width; + const coord_t gap_xy_scaled = m_flow.scaled_width(); size_t idx_object_layer_overlapping = 0; // For all intermediate layers: - for (LayersPtr::iterator it_layer = intermediate_layers.begin(); it_layer != intermediate_layers.end(); ++ it_layer) { - Layer &layer_intermediate = *(*it_layer); + for (MyLayersPtr::iterator it_layer = intermediate_layers.begin(); it_layer != intermediate_layers.end(); ++ it_layer) { + MyLayer &layer_intermediate = *(*it_layer); if (layer_intermediate.polygons.empty()) continue; // Find the overlapping object layers including the extra above / below gap. @@ -804,7 +703,7 @@ void PrintSupportMaterial::generate_base_layers( // Collect all the object layers intersecting with this layer. Polygons polygons_trimming; for (int i = idx_object_layer_overlapping; i < object.layer_count(); ++ i) { - Layer &object_layer = *object.get_layer(i); + const Layer &object_layer = *object.get_layer(i); if (object_layer.print_z > layer_intermediate.print_z + gap_extra_above - EPSILON) break; polygons_append(polygons_trimming, (Polygons)object_layer.slices); @@ -816,18 +715,17 @@ void PrintSupportMaterial::generate_base_layers( // We leave a gap equal to a full extrusion width. layer_intermediate.polygons = diff( layer_intermediate.polygons, - offset(polygons_trimming, gap_xy_scaled), - ); + offset(polygons_trimming, gap_xy_scaled)); } } // Convert some of the intermediate layers into top/bottom interface layers. -LayersPtr PrintSupportMaterial::generate_interface_layers( +PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::generate_interface_layers( const PrintObject &object, - const LayersPtr &bottom_contacts, - const LayersPtr &top_contacts, - LayersPtr &intermediate_layers, - std::deque &layer_storage) + const MyLayersPtr &bottom_contacts, + const MyLayersPtr &top_contacts, + MyLayersPtr &intermediate_layers, + MyLayerStorage &layer_storage) const { // Old comment: // Compute interface area on this layer as diff of upper contact area @@ -839,7 +737,7 @@ LayersPtr PrintSupportMaterial::generate_interface_layers( // my $area_threshold = $self->interface_flow->scaled_spacing ** 2; - LayersPtr interface_layers; + MyLayersPtr interface_layers; // Contact layer is considered an interface layer, therefore run the following block only if support_material_interface_layers > 1. if (! intermediate_layers.empty() && m_object_config->support_material_interface_layers > 1) { // Index of the first top contact layer intersecting the current intermediate layer. @@ -849,17 +747,17 @@ LayersPtr PrintSupportMaterial::generate_interface_layers( // For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers. //FIXME this could be parallelized. for (size_t idx_intermediate_layer = 0; idx_intermediate_layer < intermediate_layers.size(); ++ idx_intermediate_layer) { - Layer &intermediate_layer = intermediate_layers[idx_intermediate_layer]; + MyLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer]; // Top / bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces. coordf_t top_z = intermediate_layers[std::min(intermediate_layers.size()-1, idx_intermediate_layer + m_object_config->support_material_interface_layers - 1)]->print_z; coordf_t bottom_z = intermediate_layers[std::max(0, int(idx_intermediate_layer) - int(m_object_config->support_material_interface_layers) + 1)]->bottom_z; // Move idx_top_contact_first up until above the current print_z. - while (idx_top_contact_first < top_contacts.size() && top_contacts[idx_top_contact_first]->print_z < intermediate_layer->print_z) + while (idx_top_contact_first < top_contacts.size() && top_contacts[idx_top_contact_first]->print_z < intermediate_layer.print_z) ++ idx_top_contact_first; // Collect the top contact areas above this intermediate layer, below top_z. Polygons polygons_top_contact_projected; for (size_t idx_top_contact = idx_top_contact_first; idx_top_contact < top_contacts.size(); ++ idx_top_contact) { - const Layer &top_contact_layer = top_contacts[idx_top_contact]; + const MyLayer &top_contact_layer = *top_contacts[idx_top_contact]; if (top_contact_layer.bottom_z - EPSILON > top_z) break; polygons_append(polygons_top_contact_projected, top_contact_layer.polygons); @@ -870,8 +768,8 @@ LayersPtr PrintSupportMaterial::generate_interface_layers( // Collect the top contact areas above this intermediate layer, below top_z. Polygons polygons_bottom_contact_projected; for (size_t idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < bottom_contacts.size(); ++ idx_bottom_contact) { - const Layer &bottom_contact_layer = bottom_contacts[idx_bottom_contact]; - if (bottom_contact_layer.top_z - EPSILON > intermediate_layer.bottom_z) + const MyLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact]; + if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z) break; polygons_append(polygons_bottom_contact_projected, bottom_contact_layer.polygons); } @@ -880,20 +778,20 @@ LayersPtr PrintSupportMaterial::generate_interface_layers( continue; // Insert a new layer into top_interface_layers. - Layer &layer_new = layer_allocate(layer_storage); - layer_new.layer_type = polygons_top_contact_projected.empty() ? stlBottomInterface : sltTopInterface; + MyLayer &layer_new = layer_allocate(layer_storage, + polygons_top_contact_projected.empty() ? sltBottomInterface : sltTopInterface); layer_new.print_z = intermediate_layer.print_z; layer_new.bottom_z = intermediate_layer.bottom_z; layer_new.height = intermediate_layer.height; layer_new.bridging = intermediate_layer.bridging; - top_interface_layers.push_back(layer_new); + interface_layers.push_back(&layer_new); polygons_append(polygons_top_contact_projected, polygons_bottom_contact_projected); polygons_top_contact_projected = union_(polygons_top_contact_projected, true); - layer_new.polygons = intersection(intermediate_layers.polygons, polygons_top_contact_projected); + layer_new.polygons = intersection(intermediate_layer.polygons, polygons_top_contact_projected); //FIXME filter layer_new.polygons islands by a minimum area? // $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ]; - intermediate_layers.polygons = diff(intermediate_layers.polygons, polygons_top_contact_projected, false) + intermediate_layer.polygons = diff(intermediate_layer.polygons, polygons_top_contact_projected, false); } } @@ -905,17 +803,17 @@ void PrintSupportMaterial::generate_toolpaths( const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, const MyLayersPtr &intermediate_layers, - const MyLayersPtr &interface_layers) + const MyLayersPtr &interface_layers) const { // Shape of the top contact area. int n_contact_loops = 1; - coordf_t circle_radius = 1.5 * m_interface_flow.scaled_width; + coordf_t circle_radius = 1.5 * m_interface_flow.scaled_width(); coordf_t circle_distance = 3. * circle_radius; Polygon circle; - circle.reserve(6); + circle.points.reserve(6); for (size_t i = 0; i < 6; ++ i) { - double angle = double(i) * m_PI / 3.; - circle.push_back(Point(circle_radius * cos(angle), circle_radius * sin(angle))); + double angle = double(i) * M_PI / 3.; + circle.points.push_back(Point(circle_radius * cos(angle), circle_radius * sin(angle))); } // Slic3r::debugf "Generating patterns\n"; @@ -942,21 +840,21 @@ void PrintSupportMaterial::generate_toolpaths( std::auto_ptr filler_support = std::auto_ptr(Fill::new_from_type(infill_pattern)); { BoundingBox bbox_object = object.bounding_box(); - fill_interface->set_bounding_box(bbox_object); - fill_interface->set_bounding_box(fill_support); + filler_interface->set_bounding_box(bbox_object); + filler_support->set_bounding_box(bbox_object); } coordf_t interface_angle = m_object_config->support_material_angle + 90.; - coordf_t interface_spacing = m_object_config->support_material_interface_spacing + m_interface_flow.spacing; - coordf_t interface_density = (interface_spacing == 0.) ? 1. : (m_interface_flow.spacing / m_interface_spacing); - coordf_t support_spacing = m_object_config.object_config->support_material_spacing + m_flow.spacing; - coordf_t support_density = (support_spacing == 0.) ? 1. : (m_flow.spacing / support_spacing); + coordf_t interface_spacing = m_object_config->support_material_interface_spacing.value + m_interface_flow.spacing(); + coordf_t interface_density = (interface_spacing == 0.) ? 1. : (m_interface_flow.spacing() / interface_spacing); + coordf_t support_spacing = m_object_config->support_material_spacing.value + m_flow.spacing(); + coordf_t support_density = (support_spacing == 0.) ? 1. : (m_flow.spacing() / support_spacing); //FIXME Parallelize the support generator: /* Slic3r::parallelize( threads => $self->print_config->threads, - items => [ 0 .. n_$object->support_layers} ], + items => [ 0 .. n_$object.support_layers} ], thread_cb => sub { my $q = shift; while (defined (my $layer_id = $q->dequeue)) { @@ -964,7 +862,7 @@ void PrintSupportMaterial::generate_toolpaths( } }, no_threads_cb => sub { - $process_layer->($_) for 0 .. n_{$object->support_layers}; + $process_layer->($_) for 0 .. n_{$object.support_layers}; }, ); */ @@ -979,26 +877,30 @@ void PrintSupportMaterial::generate_toolpaths( // Find polygons with the same print_z. Polygons bottom_contact_polygons; - Polygons interface_polygons; + Polygons top_contact_polygons; Polygons base_polygons; + Polygons interface_polygons; + // Increment the layer indices to find a layer at support_layer.print_z. - for (; idx_layer_bottom_contact < bottom_contacts .size() && bottom_contacts [idx_layer_bottom_contact].print_z < support_layer.print_z - EPSILON; ++ idx_layer_bottom_contact) ; - for (; idx_layer_top_contact < top_contacts .size() && top_contacts [idx_layer_top_contact ].print_z < support_layer.print_z - EPSILON; ++ idx_layer_top_contact ) ; - for (; idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate ].print_z < support_layer.print_z - EPSILON; ++ idx_layer_intermediate ) ; - for (; idx_layer_inteface < interface_layers .size() && interface_layers [idx_layer_inteface ].print_z < support_layer.print_z - EPSILON; ++ interface_layers ) ; + for (; idx_layer_bottom_contact < bottom_contacts .size() && bottom_contacts [idx_layer_bottom_contact]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_bottom_contact) ; + for (; idx_layer_top_contact < top_contacts .size() && top_contacts [idx_layer_top_contact ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_top_contact ) ; + for (; idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_intermediate ) ; + for (; idx_layer_inteface < interface_layers .size() && interface_layers [idx_layer_inteface ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_inteface ) ; // Copy polygons from the layers. - if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact].print_z < support_layer.print_z + EPSILON) - bottom_contact_polygons = bottom_contacts[idx_layer_bottom_contact].polygons; - if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface].print_z < support_layer.print_z + EPSILON) - interface_polygons = interface_layers[idx_layer_inteface].polygons; - if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate].print_z < support_layer.print_z + EPSILON) - base_polygons = intermediate_layers[idx_layer_intermediate].polygons; + if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON) + bottom_contact_polygons = bottom_contacts[idx_layer_bottom_contact]->polygons; + if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON) + top_contact_polygons = top_contacts[idx_layer_top_contact]->polygons; + if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface]->print_z < support_layer.print_z + EPSILON) + interface_polygons = interface_layers[idx_layer_inteface]->polygons; + if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON) + base_polygons = intermediate_layers[idx_layer_intermediate]->polygons; // We redefine flows locally by applying this layer's height. Flow flow = m_flow; Flow interface_flow = m_interface_flow; - flow.set_height(layer.height); - interface_flow.set_height(layer.height); + flow.height = support_layer.height; + interface_flow.height = support_layer.height; /* if (1) { @@ -1022,10 +924,9 @@ void PrintSupportMaterial::generate_toolpaths( } Polygons contact_infill_polygons; - if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact].print_z < support_layer.print_z + EPSILON) + if (! top_contact_polygons.empty()) { // Having a top interface layer. - Polygons top_contact_polygons = top_contacts[idx_layer_top_contact].polygons; if (m_object_config->support_material_interface_layers == 0) // If no interface layers were requested, we treat the contact layer exactly as a generic base layer. polygons_append(base_polygons, top_contact_polygons); @@ -1041,7 +942,7 @@ void PrintSupportMaterial::generate_toolpaths( // Generate the outermost loop. // Find centerline of the external loop (or any other kind of extrusions should the loop be skipped) - top_contact_polygons = offset(top_contact_polygons, - 0.5 * interface_flow.scaled_width); + top_contact_polygons = offset(top_contact_polygons, - 0.5 * interface_flow.scaled_width()); Polygons loops0; { @@ -1051,35 +952,41 @@ void PrintSupportMaterial::generate_toolpaths( // Positions of the loop centers. Polygons circles; { - Polygons overhang_with_margin = offset(overhang_polygons, 0.5 * interface_flow.scaled_width); - for (Polygons::const_iterator it_contact = top_contact_polygons.begin(); it_contact != top_contact_polygons.end(); ++ it_contact) - if (! intersection_pl(it_contact->split_at_first_point, overhang_with_margin).empty()) { + Polygons overhang_with_margin = offset(overhang_polygons, 0.5 * interface_flow.scaled_width()); + for (Polygons::const_iterator it_contact = top_contact_polygons.begin(); it_contact != top_contact_polygons.end(); ++ it_contact) { + Polylines tmp; + tmp.push_back(it_contact->split_at_first_point()); + if (! intersection(tmp, overhang_with_margin).empty()) { external_loops.push_back(*it_contact); Points positions_new = it_contact->equally_spaced_points(circle_distance); for (Points::const_iterator it_center = positions_new.begin(); it_center != positions_new.end(); ++ it_center) { circles.push_back(circle); Polygon &circle_new = circles.back(); - for (size_t i = 0; i < circle_new.size(); ++ i) - circle_new[i].translate(*it_center); + for (size_t i = 0; i < circle_new.points.size(); ++ i) + circle_new.points[i].translate(*it_center); } } + } } // Apply a pattern to the loop. - @loops0 = diff(external_loops, circles); + loops0 = diff(external_loops, circles); } - // make more loops - Polygons loops = loops0; - for (size_t i = 1; i < n_contact_loops) - polygons_append(loops, offset2(loops0, - i * interface_flow.scaled_spacing - 0.5 * interface_flow.scaled_spacing, 0.5 * interface_flow.scaled_spacing)); - - // clip such loops to the side oriented towards the object + Polylines loop_lines; { - Polylines loop_lines; - loop_lines.reserve(loops.size()); - for (Polygons::const_iterator it = loops.begin(); it != loops.end(); ++ it) - loop_lines.push_back(it->split_at_first_point); - loops = intersection_pl(loop_lines, offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN))); + // make more loops + Polygons loop_polygons = loops0; + for (size_t i = 1; i < n_contact_loops; ++ i) + polygons_append(loop_polygons, + offset2( + loops0, + - int(i) * interface_flow.scaled_spacing() - 0.5 * interface_flow.scaled_spacing(), + 0.5 * interface_flow.scaled_spacing())); + // clip such loops to the side oriented towards the object + loop_lines.reserve(loop_polygons.size()); + for (Polygons::const_iterator it = loop_polygons.begin(); it != loop_polygons.end(); ++ it) + loop_lines.push_back(it->split_at_first_point()); + loop_lines = intersection(loop_lines, offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN))); } // add the contact infill area to the interface area @@ -1087,14 +994,18 @@ void PrintSupportMaterial::generate_toolpaths( // extrusions are left inside the circles; however it creates // a very large gap between loops and contact_infill_polygons, so maybe another // solution should be found to achieve both goals - contact_infill_polygons = diff(top_contact_polygons, offset(loops, circle_radius * 1.1, true)); + { + Polygons loop_polygons; + offset(loop_lines, &loop_polygons, circle_radius * 1.1); + contact_infill_polygons = diff(top_contact_polygons, loop_polygons); + } // Transform loops into ExtrusionPath objects. - for (Polylines::const_iterator it_polyline = loops.begin(); it_polyline != loops.end(); ++ it_polyline) { + for (Polylines::const_iterator it_polyline = loop_lines.begin(); it_polyline != loop_lines.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterialInterface); support_layer.support_interface_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = interface_flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = interface_flow.mm3_per_mm(); extrusion_path->width = interface_flow.width; extrusion_path->height = support_layer.height; } @@ -1104,11 +1015,11 @@ void PrintSupportMaterial::generate_toolpaths( // interface and contact infill if (! interface_polygons.empty() || ! contact_infill_polygons.empty()) { //FIXME When paralellizing, each thread shall have its own copy of the fillers. - filler_interface->set_angle(interface_angle); - filler_interface->set_spacing(interface_flow.spacing); + filler_interface->angle = interface_angle; + filler_interface->spacing = interface_flow.spacing(); // find centerline of the external loop - interface_polygons = offset2(interface_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5 * interface_flow.scaled_width); + interface_polygons = offset2(interface_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5 * interface_flow.scaled_width()); // join regions by offsetting them to ensure they're merged polygons_append(interface_polygons, contact_infill_polygons); interface_polygons = offset(interface_polygons, SCALED_EPSILON); @@ -1119,7 +1030,7 @@ void PrintSupportMaterial::generate_toolpaths( Polygons interface_polygons_new; interface_polygons_new.reserve(interface_polygons.size()); for (Polygons::iterator it_polygon = interface_polygons.begin(); it_polygon != interface_polygons.end(); ++ it_polygon) { - if (it_polygon->is_clockwise) { + if (it_polygon->is_clockwise()) { Polygons hole; hole.push_back(*it_polygon); hole.back().make_counter_clockwise(); @@ -1127,7 +1038,7 @@ void PrintSupportMaterial::generate_toolpaths( continue; } interface_polygons_new.push_back(Polygon()); - interface_polygons_new.back().swap(*it_polygon); + interface_polygons_new.back().points.swap(it_polygon->points); } interface_polygons.swap(interface_polygons_new); } @@ -1138,12 +1049,12 @@ void PrintSupportMaterial::generate_toolpaths( FillParams fill_params; fill_params.density = interface_density; fill_params.complete = true; - Polylines polylines = filler_interface->fill_surface(Surface(stInternal, *it_expolygon), fill_params); + Polylines polylines = filler_interface->fill_surface(&Surface(stInternal, *it_expolygon), fill_params); for (Polylines::const_iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterialInterface); support_layer.support_interface_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = interface_flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = interface_flow.mm3_per_mm(); extrusion_path->width = interface_flow.width; extrusion_path->height = support_layer.height; } @@ -1154,16 +1065,16 @@ void PrintSupportMaterial::generate_toolpaths( if (! base_polygons.empty()) { //FIXME When paralellizing, each thread shall have its own copy of the fillers. Fill *filler = filler_support.get(); - filler->set_angle(angles[support_layer_id % angles.size()]); + filler->angle = angles[support_layer_id % angles.size()]; // We don't use $base_flow->spacing because we need a constant spacing // value that guarantees that all layers are correctly aligned. - filler->set_spacing(flow.spacing); + filler->spacing = flow.spacing(); coordf_t density = support_density; Flow base_flow = flow; // find centerline of the external loop/extrusions - ExPolygons to_infill = offset2_ex(base_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5*flow.scaled_width); + ExPolygons to_infill = offset2_ex(base_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5*flow.scaled_width()); /* if (1) { @@ -1179,41 +1090,42 @@ void PrintSupportMaterial::generate_toolpaths( if (support_layer_id == 0) { // Base flange. filler = filler_interface.get(); - filler->set_angle(m_object_config->support_material_angle + 90.); + filler->angle = m_object_config->support_material_angle + 90.; density = 0.5; base_flow = m_first_layer_flow; // use the proper spacing for first layer as we don't need to align // its pattern to the other layers //FIXME When paralellizing, each thread shall have its own copy of the fillers. - filler->set_spacing(base_flow.spacing); + filler->spacing = base_flow.spacing(); } else if (with_sheath) { // Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove. // TODO: use brim ordering algorithm - Polygons to_infill_polygons = (Polygons)to_infill; + Polygons to_infill_polygons = to_polygons(to_infill); for (Polygons::const_iterator it_polyline = to_infill_polygons.begin(); it_polyline != to_infill_polygons.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterial); support_layer.support_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = flow.mm3_per_mm(); extrusion_path->width = flow.width; extrusion_path->height = support_layer.height; } // TODO: use offset2_ex() - to_infill = offset_ex(to_infill_polygons, - flow.scaled_spacing); + to_infill = offset_ex(to_infill_polygons, - flow.scaled_spacing()); } for (ExPolygons::const_iterator it_expolygon = to_infill.begin(); it_expolygon != to_infill.end(); ++ it_expolygon) { FillParams fill_params; fill_params.density = density; fill_params.complete = true; - Polylines polylines = filler->fill_surface(Surface(stInternal, *it_expolygon), fill_params); + Polylines polylines = filler->fill_surface(&Surface(stInternal, *it_expolygon), fill_params); for (Polylines::const_iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterial); support_layer.support_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = base_flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = base_flow.mm3_per_mm(); extrusion_path->width = base_flow.width; extrusion_path->height = support_layer.height; + } } } @@ -1221,16 +1133,16 @@ void PrintSupportMaterial::generate_toolpaths( if (! bottom_contact_polygons.empty()) { //FIXME When paralellizing, each thread shall have its own copy of the fillers. Fill *filler = filler_support.get(); - filler->set_angle(angles[support_layer_id % angles.size()]); + filler->angle = angles[support_layer_id % angles.size()]; // We don't use $base_flow->spacing because we need a constant spacing // value that guarantees that all layers are correctly aligned. - filler->set_spacing(flow.spacing); + filler->spacing = flow.spacing(); coordf_t density = support_density; Flow base_flow = flow; // find centerline of the external loop/extrusions - ExPolygons to_infill = offset2_ex(base_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5*flow.scaled_width); + ExPolygons to_infill = offset2_ex(base_polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5*flow.scaled_width()); /* if (1) { @@ -1246,41 +1158,42 @@ void PrintSupportMaterial::generate_toolpaths( if (support_layer_id == 0) { // Base flange. filler = filler_interface.get(); - filler->set_angle(m_object_config->support_material_angle + 90.); + filler->angle = m_object_config->support_material_angle + 90.; density = 0.5; base_flow = m_first_layer_flow; // use the proper spacing for first layer as we don't need to align // its pattern to the other layers //FIXME When paralellizing, each thread shall have its own copy of the fillers. - filler->set_spacing(base_flow.spacing); + filler->spacing = base_flow.spacing(); } else if (with_sheath) { // Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove. // TODO: use brim ordering algorithm - Polygons to_infill_polygons = (Polygons)to_infill; + Polygons to_infill_polygons = to_polygons(to_infill); for (Polygons::const_iterator it_polyline = to_infill_polygons.begin(); it_polyline != to_infill_polygons.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterial); support_layer.support_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = flow.mm3_per_mm(); extrusion_path->width = flow.width; extrusion_path->height = support_layer.height; } // TODO: use offset2_ex() - to_infill = offset_ex(to_infill_polygons, - flow.scaled_spacing); + to_infill = offset_ex(to_infill_polygons, - flow.scaled_spacing()); } for (ExPolygons::const_iterator it_expolygon = to_infill.begin(); it_expolygon != to_infill.end(); ++ it_expolygon) { FillParams fill_params; fill_params.density = density; fill_params.complete = true; - Polylines polylines = filler->fill_surface(Surface(stInternal, *it_expolygon), fill_params); + Polylines polylines = filler->fill_surface(&Surface(stInternal, *it_expolygon), fill_params); for (Polylines::const_iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) { ExtrusionPath *extrusion_path = new ExtrusionPath(erSupportMaterial); support_layer.support_fills.entities.push_back(extrusion_path); - extrusion_path->polyline = it_polyline->split_at_first_point; - extrusion_path->mm3_per_mm = base_flow.mm3_per_mm; + extrusion_path->polyline = *it_polyline; + extrusion_path->mm3_per_mm = base_flow.mm3_per_mm(); extrusion_path->width = base_flow.width; extrusion_path->height = support_layer.height; + } } } @@ -1295,7 +1208,7 @@ void PrintSupportMaterial::generate_toolpaths( ); } */ - }; + } // for each support_layer_id } /* diff --git a/xs/src/libslic3r/SupportMaterial.hpp b/xs/src/libslic3r/SupportMaterial.hpp index d1343e4f2..d05bf31bf 100644 --- a/xs/src/libslic3r/SupportMaterial.hpp +++ b/xs/src/libslic3r/SupportMaterial.hpp @@ -3,6 +3,8 @@ namespace Slic3r { +class PrintObject; + // how much we extend support around the actual contact area #define SUPPORT_MATERIAL_MARGIN 1.5 @@ -43,7 +45,7 @@ public: } bool operator==(const MyLayer &layer2) const { - return print_z == layer2.printz && height == layer2.height && bridging == layer2.bridging; + return print_z == layer2.print_z && height == layer2.height && bridging == layer2.bridging; } bool operator<(const MyLayer &layer2) const { @@ -90,50 +92,59 @@ public: // top or bottom extreme bool is_top; - coordf_t z() const { return is_top ? layer->print_z : layer->print_z - height; } + coordf_t z() const { return is_top ? layer->print_z : layer->print_z - layer->height; } bool operator<(const LayerExtreme &other) const { return z() < other.z(); } - } + }; struct LayerPrintZ_Hash { - static size_t operator(const MyLayer &layer) { - return std::hash(layer.print_z)^std::hash(layer.height)^size_t(layer.bridging); + size_t operator()(const MyLayer &layer) const { + return std::hash()(layer.print_z)^std::hash()(layer.height)^size_t(layer.bridging); } }; - typedef std::set MyLayersSet; - typedef std::vector MyLayersPtr; - typedef std::deque MyLayersDeque; - typedef std::deque MyLayerStorage; + typedef std::vector MyLayersPtr; + typedef std::deque MyLayerStorage; public: - PrintSupportMaterial() : - m_object(NULL), - m_print_config(NULL), - m_object_config(NULL), - m_soluble_interface(false), + PrintSupportMaterial( + const PrintConfig *print_config, + const PrintObjectConfig *object_config, + const Flow &flow, + const Flow &first_layer_flow, + const Flow &interface_flow, + bool soluble_interface) : + m_print_config(print_config), + m_object_config(object_config), + m_flow(flow), + m_first_layer_flow(first_layer_flow), + m_interface_flow(interface_flow), + m_soluble_interface(soluble_interface), m_support_layer_height_max(0.), m_support_interface_layer_height_max(0.) {} - void setup( - const PrintConfig *print_config; - const ObjectConfig *object_config; - Flow flow; - Flow first_layer_flow; - Flow interface_flow; - bool soluble_interface) - { - this->m_object = object; - this->m_print_config = print_config; - this->m_object_config = object_config; - this->m_flow = flow; - this->m_first_layer_flow = first_layer_flow; - this->m_interface_flow = interface_flow; - this->m_soluble_interface = soluble_interface; - } + PrintSupportMaterial( + PrintConfig *print_config, + PrintObjectConfig *object_config, + Flow *flow, + Flow *first_layer_flow, + Flow *interface_flow, + bool soluble_interface) : + m_print_config(print_config), + m_object_config(object_config), + m_flow(*flow), + m_first_layer_flow(*first_layer_flow), + m_interface_flow(*interface_flow), + m_soluble_interface(soluble_interface), + m_support_layer_height_max(0.), + m_support_interface_layer_height_max(0.) + {} - void generate(const PrintObject *object); + // Generate support material for the object. + // New support layers will be added to the object, + // with extrusion paths and islands filled in for each support layer. + void generate(PrintObject &object); private: // Generate top contact layers supporting overhangs. @@ -146,26 +157,29 @@ private: // otherwise set the layer height to a bridging flow of a support interface nozzle. MyLayersPtr bottom_contact_layers(const PrintObject &object, const MyLayersPtr &top_contacts, MyLayerStorage &layer_storage) const; + // Trim the top_contacts layers with the bottom_contacts layers if they overlap, so there would not be enough vertical space for both of them. + void trim_top_contacts_by_bottom_contacts(const PrintObject &object, const MyLayersPtr &bottom_contacts, MyLayersPtr &top_contacts) const; + // Generate raft layers and the intermediate support layers between the bottom contact and top contact surfaces. MyLayersPtr raft_and_intermediate_support_layers( const PrintObject &object, const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, MyLayerStorage &layer_storage, - const coordf_t max_object_layer_height); + const coordf_t max_object_layer_height) const; void generate_base_layers( const PrintObject &object, const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, - MyLayersPtr &intermediate_layers); + MyLayersPtr &intermediate_layers) const; MyLayersPtr generate_interface_layers( const PrintObject &object, const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, MyLayersPtr &intermediate_layers, - MyLayerStorage &layer_storage); + MyLayerStorage &layer_storage) const; /* void generate_pillars_shape(); @@ -178,10 +192,10 @@ private: const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, const MyLayersPtr &intermediate_layers, - const MyLayersPtr &interface_layers); + const MyLayersPtr &interface_layers) const; - const PrintConfig *m_print_config; - const ObjectConfig *m_object_config; + const PrintConfig *m_print_config; + const PrintObjectConfig *m_object_config; Flow m_flow; Flow m_first_layer_flow; Flow m_interface_flow; @@ -189,6 +203,9 @@ private: coordf_t m_support_layer_height_max; coordf_t m_support_interface_layer_height_max; + bool m_synchronize_support_layers_with_object; }; -#endif +} // namespace Slic3r + +#endif /* slic3r_SupportMaterial_hpp_ */ diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 945be6513..8305538a5 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -56,6 +56,7 @@ REGISTER_CLASS(PrintConfig, "Config::Print"); REGISTER_CLASS(FullPrintConfig, "Config::Full"); REGISTER_CLASS(Surface, "Surface"); REGISTER_CLASS(SurfaceCollection, "Surface::Collection"); +REGISTER_CLASS(PrintSupportMaterial, "Print::SupportMaterial2"); REGISTER_CLASS(TriangleMesh, "TriangleMesh"); REGISTER_CLASS(GLVertexArray, "GUI::_3DScene::GLVertexArray"); diff --git a/xs/xsp/SupportMaterial.xsp b/xs/xsp/SupportMaterial.xsp index 470cc3c61..b6925261d 100644 --- a/xs/xsp/SupportMaterial.xsp +++ b/xs/xsp/SupportMaterial.xsp @@ -1,7 +1,23 @@ %module{Slic3r::XS}; +%{ #include #include "libslic3r/SupportMaterial.hpp" +%} + +%name{Slic3r::Print::SupportMaterial2} class PrintSupportMaterial { + %name{_new} PrintSupportMaterial( + PrintConfig *print_config, + PrintObjectConfig *object_config, + Flow *flow, + Flow *first_layer_flow, + Flow *interface_flow, + bool soluble_interface); + ~PrintSupportMaterial(); + + void generate(PrintObject *object) + %code{% THIS->generate(*object); %}; +}; %package{Slic3r::Print::SupportMaterial}; %{ @@ -13,4 +29,4 @@ MARGIN() RETVAL = newSVnv(SUPPORT_MATERIAL_MARGIN); OUTPUT: RETVAL -%} \ No newline at end of file +%} diff --git a/xs/xsp/my.map b/xs/xsp/my.map index cca5649bf..d76887ac3 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -221,6 +221,10 @@ PerimeterGenerator* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T +PrintSupportMaterial* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + GLVertexArray* O_OBJECT_SLIC3R Axis T_UV diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 1c7d27a95..c9a1213d3 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -141,6 +141,10 @@ %typemap{SupportLayer*}; %typemap{Ref}{simple}; +%typemap{PrintSupportMaterial*}; +%typemap{Ref}{simple}; +%typemap{Clone}{simple}; + %typemap{PlaceholderParser*}; %typemap{Ref}{simple}; %typemap{Clone}{simple};