From ed2ee2f6f3a3f54ea1686b79a2eb88d7d81e3850 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 7 Apr 2017 17:37:30 +0200 Subject: [PATCH] Merged support_fills with support_interface_fills. When extruding supports, the support is interleaved with interface if possible (when extruded with the same extruder). Otherwise the base is extruded first. --- lib/Slic3r/GUI/Plater/2DToolpaths.pm | 1 - lib/Slic3r/Print.pm | 3 - lib/Slic3r/Print/GCode.pm | 48 ++++----- lib/Slic3r/Test/SectionCut.pm | 2 +- t/perimeters.t | 2 +- xs/src/libslic3r/ExtrusionEntity.cpp | 4 +- xs/src/libslic3r/ExtrusionEntity.hpp | 102 ++++++++++-------- .../libslic3r/ExtrusionEntityCollection.cpp | 21 ++-- .../libslic3r/ExtrusionEntityCollection.hpp | 14 ++- xs/src/libslic3r/GCode.cpp | 69 +++++++++--- xs/src/libslic3r/GCode.hpp | 1 + xs/src/libslic3r/Layer.hpp | 4 +- xs/src/libslic3r/PerimeterGenerator.cpp | 2 +- xs/src/libslic3r/Print.cpp | 2 - xs/src/slic3r/GUI/3DScene.cpp | 4 +- xs/t/07_extrusionpath.t | 4 +- xs/t/08_extrusionloop.t | 4 +- xs/xsp/ExtrusionEntityCollection.xsp | 16 +-- xs/xsp/ExtrusionLoop.xsp | 12 +-- xs/xsp/ExtrusionPath.xsp | 12 +-- xs/xsp/GCode.xsp | 1 + xs/xsp/Layer.xsp | 3 - 22 files changed, 177 insertions(+), 154 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm index 5f7ddc86c..0a4399490 100644 --- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm @@ -475,7 +475,6 @@ sub Render { if ($layer->isa('Slic3r::Layer::Support')) { $self->color([0, 0, 0]); $self->_draw($object, $print_z, $_) for @{$layer->support_fills}; - $self->_draw($object, $print_z, $_) for @{$layer->support_interface_fills}; } } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 1a4aad5b3..8a03fbb2b 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -280,9 +280,6 @@ sub make_brim { push @object_islands, (map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_fills}) if $support_layer0->support_fills; - push @object_islands, - (map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_interface_fills}) - if $support_layer0->support_interface_fills; } foreach my $copy (@{$object->_shifted_copies}) { push @islands, map { $_->translate(@$copy); $_ } map $_->clone, @object_islands; diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index 9f0421e45..7d9e33783 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -73,7 +73,6 @@ sub BUILD { || $object->config->get_abs_value('support_material_interface_speed') == 0) { foreach my $layer (@{$object->support_layers}) { push @mm3_per_mm, $layer->support_fills->min_mm3_per_mm; - push @mm3_per_mm, $layer->support_interface_fills->min_mm3_per_mm; } } } @@ -497,30 +496,31 @@ sub process_layer { # extrude support material before other things because it might use a lower Z # and also because we avoid travelling on other things when printing it - if ($layer->isa('Slic3r::Layer::Support')) { - if ($layer->support_interface_fills->count > 0) { + if ($layer->isa('Slic3r::Layer::Support') && $layer->support_fills->count > 0) { + if ($object->config->support_material_extruder == $object->config->support_material_interface_extruder) { + # Both the support and the support interface are printed with the same extruder, therefore + # the interface may be interleaved with the support base. # Don't change extruder if the extruder is set to 0. Use the current extruder instead. - $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_interface_extruder-1) - if ($object->config->support_material_interface_extruder > 0); - for my $path (@{$layer->support_interface_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { - if ($path->isa('Slic3r::ExtrusionMultiPath')) { - $gcode .= $self->_gcodegen->extrude_multipath($path, 'support material interface', $object->config->get_abs_value('support_material_interface_speed')); - } else { - $gcode .= $self->_gcodegen->extrude_path($path, 'support material interface', $object->config->get_abs_value('support_material_interface_speed')); - } - } - } - if ($layer->support_fills->count > 0) { - # Don't change extruder if the extruder is set to 0. Use the current extruder instead. - $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_extruder-1) - if ($object->config->support_material_extruder > 0); - for my $path (@{$layer->support_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { - if ($path->isa('Slic3r::ExtrusionMultiPath')) { - $gcode .= $self->_gcodegen->extrude_multipath($path, 'support material', $object->config->get_abs_value('support_material_speed')); - } else { - $gcode .= $self->_gcodegen->extrude_path($path, 'support material', $object->config->get_abs_value('support_material_speed')); - } - } + $gcode .= $self->_gcodegen->extrude_support( + $layer->support_fills->chained_path_from($self->_gcodegen->last_pos, 0), + $object->config->support_material_extruder); + } else { + # Extrude the support base before support interface for two reasons. + # 1) Support base may be extruded with the current extruder (extruder ID 0) + # and the support interface may be printed with the solube material, + # then one wants to avoid the base being printed with the soluble material. + # 2) It is likely better to print the interface after the base as the interface is + # often printed by bridges and it is convenient to have the base printed already, + # so the bridges may stick to it. + $gcode .= $self->_gcodegen->extrude_support( + $layer->support_fills->chained_path_from( + $self->_gcodegen->last_pos, 0, EXTR_ROLE_SUPPORTMATERIAL), + $object->config->support_material_extruder); + # Extrude the support interface. + $gcode .= $self->_gcodegen->extrude_support( + $layer->support_fills->chained_path_from( + $self->_gcodegen->last_pos, 0, EXTR_ROLE_SUPPORTMATERIAL_INTERFACE), + $object->config->support_material_interface_extruder); } } diff --git a/lib/Slic3r/Test/SectionCut.pm b/lib/Slic3r/Test/SectionCut.pm index 8cfda13d1..05ba41851 100644 --- a/lib/Slic3r/Test/SectionCut.pm +++ b/lib/Slic3r/Test/SectionCut.pm @@ -63,7 +63,7 @@ sub export_svg { # plot support material $self->_svg_style->{'stroke'} = '#12EF00'; $self->_svg_style->{'fill'} = '#22FF00'; - $self->_plot_group(sub { $_[0]->isa('Slic3r::Layer::Support') ? ($_[0]->support_fills, $_[0]->support_interface_fills) : () }); + $self->_plot_group(sub { $_[0]->isa('Slic3r::Layer::Support') ? ($_[0]->support_fills) : () }); Slic3r::open(\my $fh, '>', $filename); print $fh $svg->xmlify; diff --git a/t/perimeters.t b/t/perimeters.t index 47b844887..b328b2b5f 100644 --- a/t/perimeters.t +++ b/t/perimeters.t @@ -65,7 +65,7 @@ use Slic3r::Test; $expected{external}, 'expected number of external loops'; is_deeply [ map { ($_->role == EXTR_ROLE_EXTERNAL_PERIMETER) || 0 } map @$_, @loops ], $expected{ext_order}, 'expected external order'; - is scalar(grep $_->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER, @loops), + is scalar(grep $_->loop_role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER, @loops), $expected{cinternal}, 'expected number of internal contour loops'; is scalar(grep $_->polygon->is_counter_clockwise, @loops), $expected{ccw}, 'expected number of ccw loops'; diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index 880dcaad0..5ed56d17b 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -241,8 +241,8 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang) // now split path_idx in two parts const ExtrusionPath &path = this->paths[path_idx]; - ExtrusionPath p1(path.role, path.mm3_per_mm, path.width, path.height); - ExtrusionPath p2(path.role, path.mm3_per_mm, path.width, path.height); + ExtrusionPath p1(path.role(), path.mm3_per_mm, path.width, path.height); + ExtrusionPath p2(path.role(), path.mm3_per_mm, path.width, path.height); path.polyline.split_at(p, &p1.polyline, &p2.polyline); if (this->paths.size() == 1) { diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index c4c95bbbc..dc0dcdd34 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -25,6 +25,8 @@ enum ExtrusionRole { erSkirt, erSupportMaterial, erSupportMaterialInterface, + // Extrusion role for a collection with multiple extrusion roles. + erMixed, }; /* Special flags describing loop */ @@ -37,6 +39,7 @@ enum ExtrusionLoopRole { class ExtrusionEntity { public: + virtual ExtrusionRole role() const = 0; virtual bool is_collection() const { return false; } virtual bool is_loop() const { return false; } virtual bool can_reverse() const { return true; } @@ -68,7 +71,6 @@ class ExtrusionPath : public ExtrusionEntity { public: Polyline polyline; - ExtrusionRole role; // Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator. double mm3_per_mm; // Width of the extrusion, used for visualization purposes. @@ -76,14 +78,14 @@ public: // Height of the extrusion, used for visualization purposed. float height; - ExtrusionPath(ExtrusionRole role) : role(role), mm3_per_mm(-1), width(-1), height(-1) {}; - ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : role(role), mm3_per_mm(mm3_per_mm), width(width), height(height) {}; - ExtrusionPath(const ExtrusionPath &rhs) : role(rhs.role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(rhs.polyline) {} - ExtrusionPath(ExtrusionPath &&rhs) : role(rhs.role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(std::move(rhs.polyline)) {} -// ExtrusionPath(ExtrusionRole role, const Flow &flow) : role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height) {}; + ExtrusionPath(ExtrusionRole role) : m_role(role), mm3_per_mm(-1), width(-1), height(-1) {}; + ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : m_role(role), mm3_per_mm(mm3_per_mm), width(width), height(height) {}; + ExtrusionPath(const ExtrusionPath &rhs) : m_role(rhs.m_role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(rhs.polyline) {} + ExtrusionPath(ExtrusionPath &&rhs) : m_role(rhs.m_role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(std::move(rhs.polyline)) {} +// ExtrusionPath(ExtrusionRole role, const Flow &flow) : m_role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height) {}; - ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->role = rhs.role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = rhs.polyline; return *this; } - ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->role = rhs.role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = std::move(rhs.polyline); return *this; } + ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = rhs.polyline; return *this; } + ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = std::move(rhs.polyline); return *this; } ExtrusionPath* clone() const { return new ExtrusionPath (*this); } void reverse() { this->polyline.reverse(); } @@ -98,25 +100,26 @@ public: void clip_end(double distance); void simplify(double tolerance); virtual double length() const; + virtual ExtrusionRole role() const { return m_role; } bool is_perimeter() const { - return this->role == erPerimeter - || this->role == erExternalPerimeter - || this->role == erOverhangPerimeter; + return this->m_role == erPerimeter + || this->m_role == erExternalPerimeter + || this->m_role == erOverhangPerimeter; } bool is_infill() const { - return this->role == erBridgeInfill - || this->role == erInternalInfill - || this->role == erSolidInfill - || this->role == erTopSolidInfill; + return this->m_role == erBridgeInfill + || this->m_role == erInternalInfill + || this->m_role == erSolidInfill + || this->m_role == erTopSolidInfill; } bool is_solid_infill() const { - return this->role == erBridgeInfill - || this->role == erSolidInfill - || this->role == erTopSolidInfill; + return this->m_role == erBridgeInfill + || this->m_role == erSolidInfill + || this->m_role == erTopSolidInfill; } bool is_bridge() const { - return this->role == erBridgeInfill - || this->role == erOverhangPerimeter; + return this->m_role == erBridgeInfill + || this->m_role == erOverhangPerimeter; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. @@ -133,8 +136,10 @@ public: double min_mm3_per_mm() const { return this->mm3_per_mm; } Polyline as_polyline() const { return this->polyline; } - private: +private: void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; + + ExtrusionRole m_role; }; typedef std::vector ExtrusionPaths; @@ -161,21 +166,22 @@ public: Point first_point() const { return this->paths.front().polyline.points.front(); } Point last_point() const { return this->paths.back().polyline.points.back(); } virtual double length() const; + virtual ExtrusionRole role() const { return this->paths.empty() ? erNone : this->paths.front().role(); } bool is_perimeter() const { - return this->paths.front().role == erPerimeter - || this->paths.front().role == erExternalPerimeter - || this->paths.front().role == erOverhangPerimeter; + return this->paths.front().role() == erPerimeter + || this->paths.front().role() == erExternalPerimeter + || this->paths.front().role() == erOverhangPerimeter; } bool is_infill() const { - return this->paths.front().role == erBridgeInfill - || this->paths.front().role == erInternalInfill - || this->paths.front().role == erSolidInfill - || this->paths.front().role == erTopSolidInfill; + return this->paths.front().role() == erBridgeInfill + || this->paths.front().role() == erInternalInfill + || this->paths.front().role() == erSolidInfill + || this->paths.front().role() == erTopSolidInfill; } bool is_solid_infill() const { - return this->paths.front().role == erBridgeInfill - || this->paths.front().role == erSolidInfill - || this->paths.front().role == erTopSolidInfill; + return this->paths.front().role() == erBridgeInfill + || this->paths.front().role() == erSolidInfill + || this->paths.front().role() == erTopSolidInfill; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. @@ -196,15 +202,14 @@ public: // Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging. class ExtrusionLoop : public ExtrusionEntity { - public: +public: ExtrusionPaths paths; - ExtrusionLoopRole role; - ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : role(role) {}; + ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {}; ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) - : paths(paths), role(role) {}; + : paths(paths), m_loop_role(role) {}; ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) - : role(role) { + : m_loop_role(role) { this->paths.push_back(path); }; bool is_loop() const { return true; } @@ -223,21 +228,23 @@ class ExtrusionLoop : public ExtrusionEntity // Test, whether the point is extruded by a bridging flow. // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead. bool has_overhang_point(const Point &point) const; + virtual ExtrusionRole role() const { return this->paths.empty() ? erNone : this->paths.front().role(); } + ExtrusionLoopRole loop_role() const { return m_loop_role; } bool is_perimeter() const { - return this->paths.front().role == erPerimeter - || this->paths.front().role == erExternalPerimeter - || this->paths.front().role == erOverhangPerimeter; + return this->paths.front().role() == erPerimeter + || this->paths.front().role() == erExternalPerimeter + || this->paths.front().role() == erOverhangPerimeter; } bool is_infill() const { - return this->paths.front().role == erBridgeInfill - || this->paths.front().role == erInternalInfill - || this->paths.front().role == erSolidInfill - || this->paths.front().role == erTopSolidInfill; + return this->paths.front().role() == erBridgeInfill + || this->paths.front().role() == erInternalInfill + || this->paths.front().role() == erSolidInfill + || this->paths.front().role() == erTopSolidInfill; } bool is_solid_infill() const { - return this->paths.front().role == erBridgeInfill - || this->paths.front().role == erSolidInfill - || this->paths.front().role == erTopSolidInfill; + return this->paths.front().role() == erBridgeInfill + || this->paths.front().role() == erSolidInfill + || this->paths.front().role() == erTopSolidInfill; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. @@ -253,6 +260,9 @@ class ExtrusionLoop : public ExtrusionEntity // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const; Polyline as_polyline() const { return this->polygon().split_at_first_point(); } + +private: + ExtrusionLoopRole m_loop_role; }; inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height) diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.cpp b/xs/src/libslic3r/ExtrusionEntityCollection.cpp index 2e70a1a28..93dd8dfb8 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.cpp @@ -22,7 +22,7 @@ ExtrusionEntityCollection& ExtrusionEntityCollection::operator= (const Extrusion } void -ExtrusionEntityCollection::swap (ExtrusionEntityCollection &c) +ExtrusionEntityCollection::swap(ExtrusionEntityCollection &c) { std::swap(this->entities, c.entities); std::swap(this->orig_indices, c.orig_indices); @@ -81,22 +81,22 @@ ExtrusionEntityCollection::remove(size_t i) } ExtrusionEntityCollection -ExtrusionEntityCollection::chained_path(bool no_reverse, std::vector* orig_indices) const +ExtrusionEntityCollection::chained_path(bool no_reverse, ExtrusionRole role) const { ExtrusionEntityCollection coll; - this->chained_path(&coll, no_reverse, orig_indices); + this->chained_path(&coll, no_reverse, role); return coll; } void -ExtrusionEntityCollection::chained_path(ExtrusionEntityCollection* retval, bool no_reverse, std::vector* orig_indices) const +ExtrusionEntityCollection::chained_path(ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector* orig_indices) const { if (this->entities.empty()) return; - this->chained_path_from(this->entities.front()->first_point(), retval, no_reverse, orig_indices); + this->chained_path_from(this->entities.front()->first_point(), retval, no_reverse, role, orig_indices); } void -ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse, std::vector* orig_indices) const +ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector* orig_indices) const { if (this->no_sort) { *retval = *this; @@ -110,6 +110,15 @@ ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCo ExtrusionEntitiesPtr my_paths; for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) { + if (role != erMixed) { + // The caller wants only paths with a specific extrusion role. + auto role2 = (*it)->role(); + if (role != role2) { + // This extrusion entity does not match the role asked. + assert(role2 != erMixed); + continue; + } + } ExtrusionEntity* entity = (*it)->clone(); my_paths.push_back(entity); if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin(); diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index adc043d1e..07e206214 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -24,6 +24,14 @@ public: explicit operator ExtrusionPaths() const; bool is_collection() const { return true; }; + virtual ExtrusionRole role() const { + ExtrusionRole out = erNone; + for (const ExtrusionEntity *ee : entities) { + ExtrusionRole er = ee->role(); + out = (out == erNone || out == er) ? er : erMixed; + } + return out; + } bool can_reverse() const { return !this->no_sort; }; bool empty() const { return this->entities.empty(); }; void clear(); @@ -49,9 +57,9 @@ public: } void replace(size_t i, const ExtrusionEntity &entity); void remove(size_t i); - ExtrusionEntityCollection chained_path(bool no_reverse = false, std::vector* orig_indices = NULL) const; - void chained_path(ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector* orig_indices = NULL) const; - void chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector* orig_indices = NULL) const; + ExtrusionEntityCollection chained_path(bool no_reverse = false, ExtrusionRole role = erMixed) const; + void chained_path(ExtrusionEntityCollection* retval, bool no_reverse = false, ExtrusionRole role = erMixed, std::vector* orig_indices = nullptr) const; + void chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse = false, ExtrusionRole role = erMixed, std::vector* orig_indices = nullptr) const; void reverse(); Point first_point() const { return this->entities.front()->first_point(); } Point last_point() const { return this->entities.back()->last_point(); } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 1fffc1f97..5d58ec404 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -354,6 +354,7 @@ static inline const char* ExtrusionRole2String(const ExtrusionRole role) case erSkirt: return "erSkirt"; case erSupportMaterial: return "erSupportMaterial"; case erSupportMaterialInterface: return "erSupportMaterialInterface"; + case erMixed: return "erMixed"; default: return "erInvalid"; }; } @@ -565,7 +566,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) bool was_clockwise = loop.make_counter_clockwise(); SeamPosition seam_position = this->config.seam_position; - if (loop.role == elrSkirt) + if (loop.loop_role() == elrSkirt) seam_position = spNearest; // find the point of the loop that is closest to the current extruder position @@ -715,7 +716,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) loop.split_at(polygon.points[idx_min], true); } else if (seam_position == spRandom) { - if (loop.role == elrContourInternalPerimeter) { + if (loop.loop_role() == elrContourInternalPerimeter) { // This loop does not contain any other loop. Set a random position. // The other loops will get a seam close to the random point chosen // on the inner most contour. @@ -750,7 +751,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) // extrude along the path std::string gcode; for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) { -// description += ExtrusionLoopRole2String(loop.role); +// description += ExtrusionLoopRole2String(loop.loop_role()); // description += ExtrusionRole2String(path->role); path->simplify(SCALED_RESOLUTION); gcode += this->_extrude(*path, description, speed); @@ -763,7 +764,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) this->wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path // make a little move inwards before leaving loop - if (paths.back().role == erExternalPerimeter && this->layer != NULL && this->config.perimeters > 1) { + if (paths.back().role() == erExternalPerimeter && this->layer != NULL && this->config.perimeters > 1) { // detect angle between last and first segment // the side depends on the original winding order of the polygon (left for contours, right for holes) Point a = paths.front().polyline.points[1]; // second point @@ -805,7 +806,7 @@ GCode::extrude(ExtrusionMultiPath multipath, std::string description, double spe // extrude along the path std::string gcode; for (ExtrusionPaths::iterator path = multipath.paths.begin(); path != multipath.paths.end(); ++path) { -// description += ExtrusionLoopRole2String(loop.role); +// description += ExtrusionLoopRole2String(loop.loop_role()); // description += ExtrusionRole2String(path->role); path->simplify(SCALED_RESOLUTION); gcode += this->_extrude(*path, description, speed); @@ -837,7 +838,7 @@ GCode::extrude(const ExtrusionEntity &entity, std::string description, double sp std::string GCode::extrude(ExtrusionPath path, std::string description, double speed) { -// description += ExtrusionRole2String(path.role); +// description += ExtrusionRole2String(path.role()); path.simplify(SCALED_RESOLUTION); std::string gcode = this->_extrude(path, description, speed); if (this->wipe.enable) { @@ -849,6 +850,40 @@ GCode::extrude(ExtrusionPath path, std::string description, double speed) return gcode; } +std::string GCode::extrude_support(const ExtrusionEntityCollection *support_fills, unsigned int extruder_id) +{ + std::string gcode; + if (! support_fills->entities.empty()) { + const char *support_label = "support material"; + const char *support_interface_label = "support material interface"; + const double support_speed = this->config.get_abs_value("support_material_speed"); + const double support_interface_speed = this->config.get_abs_value("support_material_interface_speed"); + // Only trigger extruder change if the extruder is not set to zero, + // but make sure the extruder is initialized. + // Extruder ID zero means "does not matter", extrude with the current extruder. + if (this->writer.extruder() == nullptr && extruder_id == 0) + extruder_id = 1; + if (extruder_id > 0) + gcode += this->set_extruder(extruder_id - 1); + for (const ExtrusionEntity *ee : support_fills->entities) { + ExtrusionRole role = ee->role(); + assert(role == erSupportMaterial || role == erSupportMaterialInterface); + const char *label = (role == erSupportMaterial) ? support_label : support_interface_label; + const double speed = (role == erSupportMaterial) ? support_speed : support_interface_speed; + const ExtrusionPath *path = dynamic_cast(ee); + if (path) + gcode += this->extrude(*path, label, speed); + else { + const ExtrusionMultiPath *multipath = dynamic_cast(ee); + assert(multipath != nullptr); + if (multipath) + gcode += this->extrude(*multipath, label, speed); + } + } + } + return gcode; +} + std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed) { @@ -858,7 +893,7 @@ GCode::_extrude(const ExtrusionPath &path, std::string description, double speed if (!this->_last_pos_defined || !this->_last_pos.coincides_with(path.first_point())) { gcode += this->travel_to( path.first_point(), - path.role, + path.role(), "move to first " + description + " point" ); } @@ -889,19 +924,19 @@ GCode::_extrude(const ExtrusionPath &path, std::string description, double speed // set speed if (speed == -1) { - if (path.role == erPerimeter) { + if (path.role() == erPerimeter) { speed = this->config.get_abs_value("perimeter_speed"); - } else if (path.role == erExternalPerimeter) { + } else if (path.role() == erExternalPerimeter) { speed = this->config.get_abs_value("external_perimeter_speed"); - } else if (path.role == erOverhangPerimeter || path.role == erBridgeInfill) { + } else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) { speed = this->config.get_abs_value("bridge_speed"); - } else if (path.role == erInternalInfill) { + } else if (path.role() == erInternalInfill) { speed = this->config.get_abs_value("infill_speed"); - } else if (path.role == erSolidInfill) { + } else if (path.role() == erSolidInfill) { speed = this->config.get_abs_value("solid_infill_speed"); - } else if (path.role == erTopSolidInfill) { + } else if (path.role() == erTopSolidInfill) { speed = this->config.get_abs_value("top_solid_infill_speed"); - } else if (path.role == erGapFill) { + } else if (path.role() == erGapFill) { speed = this->config.get_abs_value("gap_fill_speed"); } else { CONFESS("Invalid speed"); @@ -931,10 +966,10 @@ GCode::_extrude(const ExtrusionPath &path, std::string description, double speed // extrude arc or line if (this->enable_extrusion_role_markers || this->enable_analyzer_markers) { - if (path.role != this->_last_extrusion_role) { - this->_last_extrusion_role = path.role; + if (path.role() != this->_last_extrusion_role) { + this->_last_extrusion_role = path.role(); char buf[32]; - sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role)); + sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role())); gcode += buf; } } diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 8fe94edc9..b973bf95d 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -123,6 +123,7 @@ class GCode { std::string extrude(ExtrusionLoop loop, std::string description = "", double speed = -1); std::string extrude(ExtrusionMultiPath multipath, std::string description = "", double speed = -1); std::string extrude(ExtrusionPath path, std::string description = "", double speed = -1); + std::string extrude_support(const ExtrusionEntityCollection *support_fills, unsigned int extruder_id); std::string travel_to(const Point &point, ExtrusionRole role, std::string comment); bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone); std::string retract(bool toolchange = false); diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index dd0f0143a..5aefac6f8 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -143,10 +143,8 @@ class SupportLayer : public Layer { public: // Polygons covered by the supports: base, interface and contact areas. ExPolygonCollection support_islands; - // Extrusion paths for the support base. + // Extrusion paths for the support base and for the support interface and contacts. ExtrusionEntityCollection support_fills; - // Extrusion paths for the support interface and contacts. - ExtrusionEntityCollection support_interface_fills; protected: SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index 871ded2c2..065d3b2b7 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -391,7 +391,7 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops, // sort entities into a new collection using a nearest-neighbor search, // preserving the original indices which are useful for detecting thin walls ExtrusionEntityCollection sorted_coll; - coll.chained_path(&sorted_coll, false, &sorted_coll.orig_indices); + coll.chained_path(&sorted_coll, false, erMixed, &sorted_coll.orig_indices); // traverse children and build the final collection ExtrusionEntityCollection entities; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index f327a095a..3b2d64177 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -903,8 +903,6 @@ void Print::_make_skirt() break; for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities) append(object_points, extrusion_entity->as_polyline().points); - for (const ExtrusionEntity *extrusion_entity : layer->support_interface_fills.entities) - append(object_points, extrusion_entity->as_polyline().points); } // Repeat points for each object copy. for (const Point &shift : object->_shifted_copies) { diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 9929655f5..8cccbd212 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -835,10 +835,8 @@ void _3DScene::_load_print_object_toolpaths( } if (ctxt.has_support) { const SupportLayer *support_layer = dynamic_cast(layer); - if (support_layer) { + if (support_layer) extrusionentity_to_verts(support_layer->support_fills, float(layer->print_z), copy, *vols[2]); - extrusionentity_to_verts(support_layer->support_interface_fills, float(layer->print_z), copy, *vols[2]); - } } } for (size_t i = 0; i < 3; ++ i) { diff --git a/xs/t/07_extrusionpath.t b/xs/t/07_extrusionpath.t index 1c2ed3f2d..008b51b00 100644 --- a/xs/t/07_extrusionpath.t +++ b/xs/t/07_extrusionpath.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 8; +use Test::More tests => 7; my $points = [ [100, 100], @@ -34,7 +34,5 @@ ok $path->first_point->coincides_with($path->polyline->[0]), 'first_point'; $path = $path->clone; is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; -$path->role(Slic3r::ExtrusionPath::EXTR_ROLE_FILL); -is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_FILL, 'modify role'; __END__ diff --git a/xs/t/08_extrusionloop.t b/xs/t/08_extrusionloop.t index 92d720dc3..e0660a9fd 100644 --- a/xs/t/08_extrusionloop.t +++ b/xs/t/08_extrusionloop.t @@ -5,7 +5,7 @@ use warnings; use List::Util qw(sum); use Slic3r::XS; -use Test::More tests => 48; +use Test::More tests => 47; { my $square = [ @@ -35,8 +35,6 @@ use Test::More tests => 48; my $path = $loop->[0]; isa_ok $path, 'Slic3r::ExtrusionPath::Ref'; is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; - $path->role(Slic3r::ExtrusionPath::EXTR_ROLE_FILL); - is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_FILL, 'modify role'; } $loop->split_at_vertex($square_p->[2]); diff --git a/xs/xsp/ExtrusionEntityCollection.xsp b/xs/xsp/ExtrusionEntityCollection.xsp index cd8700df7..731232358 100644 --- a/xs/xsp/ExtrusionEntityCollection.xsp +++ b/xs/xsp/ExtrusionEntityCollection.xsp @@ -12,15 +12,15 @@ %code{% RETVAL = THIS->clone(); %}; void reverse(); void clear(); - ExtrusionEntityCollection* chained_path(bool no_reverse) + ExtrusionEntityCollection* chained_path(bool no_reverse, ExtrusionRole role = erMixed) %code{% RETVAL = new ExtrusionEntityCollection(); - THIS->chained_path(RETVAL, no_reverse); + THIS->chained_path(RETVAL, no_reverse, role); %}; - ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse) + ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse, ExtrusionRole role = erMixed) %code{% RETVAL = new ExtrusionEntityCollection(); - THIS->chained_path_from(*start_near, RETVAL, no_reverse); + THIS->chained_path_from(*start_near, RETVAL, no_reverse, role); %}; Clone first_point(); Clone last_point(); @@ -100,13 +100,5 @@ ExtrusionEntityCollection::no_sort(...) OUTPUT: RETVAL -ExtrusionEntityCollection* -ExtrusionEntityCollection::chained_path_indices(bool no_reverse) - CODE: - RETVAL = new ExtrusionEntityCollection(); - THIS->chained_path(RETVAL, no_reverse, &RETVAL->orig_indices); - OUTPUT: - RETVAL - %} }; diff --git a/xs/xsp/ExtrusionLoop.xsp b/xs/xsp/ExtrusionLoop.xsp index 21bfb350c..85a204381 100644 --- a/xs/xsp/ExtrusionLoop.xsp +++ b/xs/xsp/ExtrusionLoop.xsp @@ -27,6 +27,8 @@ %code{% THIS->clip_end(distance, &RETVAL); %}; bool has_overhang_point(Point* point) %code{% RETVAL = THIS->has_overhang_point(*point); %}; + ExtrusionRole role() const; + ExtrusionLoopRole loop_role() const; bool is_perimeter(); bool is_infill(); bool is_solid_infill(); @@ -46,16 +48,6 @@ ExtrusionLoop::arrayref() OUTPUT: RETVAL -ExtrusionLoopRole -ExtrusionLoop::role(...) - CODE: - if (items > 1) { - THIS->role = (ExtrusionLoopRole)SvUV(ST(1)); - } - RETVAL = THIS->role; - OUTPUT: - RETVAL - %} }; diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp index f050f866f..ff4316d44 100644 --- a/xs/xsp/ExtrusionPath.xsp +++ b/xs/xsp/ExtrusionPath.xsp @@ -22,6 +22,7 @@ void clip_end(double distance); void simplify(double tolerance); double length(); + ExtrusionRole role() const; bool is_perimeter(); bool is_infill(); bool is_solid_infill(); @@ -57,16 +58,6 @@ ExtrusionPath::polyline(...) OUTPUT: RETVAL -ExtrusionRole -ExtrusionPath::role(...) - CODE: - if (items > 1) { - THIS->role = (ExtrusionRole)SvUV(ST(1)); - } - RETVAL = THIS->role; - OUTPUT: - RETVAL - double ExtrusionPath::mm3_per_mm(...) CODE: @@ -143,6 +134,7 @@ _constant() EXTR_ROLE_SKIRT = erSkirt EXTR_ROLE_SUPPORTMATERIAL = erSupportMaterial EXTR_ROLE_SUPPORTMATERIAL_INTERFACE = erSupportMaterialInterface + EXTR_ROLE_MIXED = erMixed PROTOTYPE: CODE: RETVAL = ix; diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp index 78f1f9d1f..58c12170e 100644 --- a/xs/xsp/GCode.xsp +++ b/xs/xsp/GCode.xsp @@ -181,6 +181,7 @@ %code{% RETVAL = THIS->extrude(*multipath, description, speed); %}; %name{extrude_path} std::string extrude(ExtrusionPath* path, std::string description = "", double speed = -1) %code{% RETVAL = THIS->extrude(*path, description, speed); %}; + std::string extrude_support(ExtrusionEntityCollection *support_fills, unsigned int extruder_id); std::string travel_to(Point* point, ExtrusionRole role, std::string comment) %code{% RETVAL = THIS->travel_to(*point, role, comment); %}; bool needs_retraction(Polyline* travel, ExtrusionRole role = erNone) diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 469778f04..55e52eca4 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -110,9 +110,6 @@ %code%{ RETVAL = &THIS->support_islands; %}; Ref support_fills() %code%{ RETVAL = &THIS->support_fills; %}; - Ref support_interface_fills() - %code%{ RETVAL = &THIS->support_interface_fills; %}; - // copies of some Layer methods, because the parameter wrapper code // gets confused about getting a Layer::Support instead of a Layer