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.
This commit is contained in:
bubnikv 2017-04-07 17:37:30 +02:00
parent c40de7e424
commit ed2ee2f6f3
22 changed files with 177 additions and 154 deletions

View File

@ -475,7 +475,6 @@ sub Render {
if ($layer->isa('Slic3r::Layer::Support')) { if ($layer->isa('Slic3r::Layer::Support')) {
$self->color([0, 0, 0]); $self->color([0, 0, 0]);
$self->_draw($object, $print_z, $_) for @{$layer->support_fills}; $self->_draw($object, $print_z, $_) for @{$layer->support_fills};
$self->_draw($object, $print_z, $_) for @{$layer->support_interface_fills};
} }
} }
} }

View File

@ -280,9 +280,6 @@ sub make_brim {
push @object_islands, push @object_islands,
(map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_fills}) (map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_fills})
if $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}) { foreach my $copy (@{$object->_shifted_copies}) {
push @islands, map { $_->translate(@$copy); $_ } map $_->clone, @object_islands; push @islands, map { $_->translate(@$copy); $_ } map $_->clone, @object_islands;

View File

@ -73,7 +73,6 @@ sub BUILD {
|| $object->config->get_abs_value('support_material_interface_speed') == 0) { || $object->config->get_abs_value('support_material_interface_speed') == 0) {
foreach my $layer (@{$object->support_layers}) { foreach my $layer (@{$object->support_layers}) {
push @mm3_per_mm, $layer->support_fills->min_mm3_per_mm; 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 # 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 # and also because we avoid travelling on other things when printing it
if ($layer->isa('Slic3r::Layer::Support')) { if ($layer->isa('Slic3r::Layer::Support') && $layer->support_fills->count > 0) {
if ($layer->support_interface_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. # 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) $gcode .= $self->_gcodegen->extrude_support(
if ($object->config->support_material_interface_extruder > 0); $layer->support_fills->chained_path_from($self->_gcodegen->last_pos, 0),
for my $path (@{$layer->support_interface_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { $object->config->support_material_extruder);
if ($path->isa('Slic3r::ExtrusionMultiPath')) {
$gcode .= $self->_gcodegen->extrude_multipath($path, 'support material interface', $object->config->get_abs_value('support_material_interface_speed'));
} else { } else {
$gcode .= $self->_gcodegen->extrude_path($path, 'support material interface', $object->config->get_abs_value('support_material_interface_speed')); # 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.
if ($layer->support_fills->count > 0) { # 2) It is likely better to print the interface after the base as the interface is
# Don't change extruder if the extruder is set to 0. Use the current extruder instead. # often printed by bridges and it is convenient to have the base printed already,
$gcode .= $self->_gcodegen->set_extruder($object->config->support_material_extruder-1) # so the bridges may stick to it.
if ($object->config->support_material_extruder > 0); $gcode .= $self->_gcodegen->extrude_support(
for my $path (@{$layer->support_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { $layer->support_fills->chained_path_from(
if ($path->isa('Slic3r::ExtrusionMultiPath')) { $self->_gcodegen->last_pos, 0, EXTR_ROLE_SUPPORTMATERIAL),
$gcode .= $self->_gcodegen->extrude_multipath($path, 'support material', $object->config->get_abs_value('support_material_speed')); $object->config->support_material_extruder);
} else { # Extrude the support interface.
$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, EXTR_ROLE_SUPPORTMATERIAL_INTERFACE),
$object->config->support_material_interface_extruder);
} }
} }

View File

@ -63,7 +63,7 @@ sub export_svg {
# plot support material # plot support material
$self->_svg_style->{'stroke'} = '#12EF00'; $self->_svg_style->{'stroke'} = '#12EF00';
$self->_svg_style->{'fill'} = '#22FF00'; $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); Slic3r::open(\my $fh, '>', $filename);
print $fh $svg->xmlify; print $fh $svg->xmlify;

View File

@ -65,7 +65,7 @@ use Slic3r::Test;
$expected{external}, 'expected number of external loops'; $expected{external}, 'expected number of external loops';
is_deeply [ map { ($_->role == EXTR_ROLE_EXTERNAL_PERIMETER) || 0 } map @$_, @loops ], is_deeply [ map { ($_->role == EXTR_ROLE_EXTERNAL_PERIMETER) || 0 } map @$_, @loops ],
$expected{ext_order}, 'expected external order'; $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'; $expected{cinternal}, 'expected number of internal contour loops';
is scalar(grep $_->polygon->is_counter_clockwise, @loops), is scalar(grep $_->polygon->is_counter_clockwise, @loops),
$expected{ccw}, 'expected number of ccw loops'; $expected{ccw}, 'expected number of ccw loops';

View File

@ -241,8 +241,8 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
// now split path_idx in two parts // now split path_idx in two parts
const ExtrusionPath &path = this->paths[path_idx]; const ExtrusionPath &path = this->paths[path_idx];
ExtrusionPath p1(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); ExtrusionPath p2(path.role(), path.mm3_per_mm, path.width, path.height);
path.polyline.split_at(p, &p1.polyline, &p2.polyline); path.polyline.split_at(p, &p1.polyline, &p2.polyline);
if (this->paths.size() == 1) { if (this->paths.size() == 1) {

View File

@ -25,6 +25,8 @@ enum ExtrusionRole {
erSkirt, erSkirt,
erSupportMaterial, erSupportMaterial,
erSupportMaterialInterface, erSupportMaterialInterface,
// Extrusion role for a collection with multiple extrusion roles.
erMixed,
}; };
/* Special flags describing loop */ /* Special flags describing loop */
@ -37,6 +39,7 @@ enum ExtrusionLoopRole {
class ExtrusionEntity class ExtrusionEntity
{ {
public: public:
virtual ExtrusionRole role() const = 0;
virtual bool is_collection() const { return false; } virtual bool is_collection() const { return false; }
virtual bool is_loop() const { return false; } virtual bool is_loop() const { return false; }
virtual bool can_reverse() const { return true; } virtual bool can_reverse() const { return true; }
@ -68,7 +71,6 @@ class ExtrusionPath : public ExtrusionEntity
{ {
public: public:
Polyline polyline; Polyline polyline;
ExtrusionRole role;
// Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator. // Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator.
double mm3_per_mm; double mm3_per_mm;
// Width of the extrusion, used for visualization purposes. // Width of the extrusion, used for visualization purposes.
@ -76,14 +78,14 @@ public:
// Height of the extrusion, used for visualization purposed. // Height of the extrusion, used for visualization purposed.
float height; float height;
ExtrusionPath(ExtrusionRole role) : role(role), mm3_per_mm(-1), width(-1), height(-1) {}; 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) : role(role), mm3_per_mm(mm3_per_mm), width(width), height(height) {}; 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) : role(rhs.role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(rhs.polyline) {} 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) : role(rhs.role), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), polyline(std::move(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) : role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height) {}; // 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=(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->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=(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); } ExtrusionPath* clone() const { return new ExtrusionPath (*this); }
void reverse() { this->polyline.reverse(); } void reverse() { this->polyline.reverse(); }
@ -98,25 +100,26 @@ public:
void clip_end(double distance); void clip_end(double distance);
void simplify(double tolerance); void simplify(double tolerance);
virtual double length() const; virtual double length() const;
virtual ExtrusionRole role() const { return m_role; }
bool is_perimeter() const { bool is_perimeter() const {
return this->role == erPerimeter return this->m_role == erPerimeter
|| this->role == erExternalPerimeter || this->m_role == erExternalPerimeter
|| this->role == erOverhangPerimeter; || this->m_role == erOverhangPerimeter;
} }
bool is_infill() const { bool is_infill() const {
return this->role == erBridgeInfill return this->m_role == erBridgeInfill
|| this->role == erInternalInfill || this->m_role == erInternalInfill
|| this->role == erSolidInfill || this->m_role == erSolidInfill
|| this->role == erTopSolidInfill; || this->m_role == erTopSolidInfill;
} }
bool is_solid_infill() const { bool is_solid_infill() const {
return this->role == erBridgeInfill return this->m_role == erBridgeInfill
|| this->role == erSolidInfill || this->m_role == erSolidInfill
|| this->role == erTopSolidInfill; || this->m_role == erTopSolidInfill;
} }
bool is_bridge() const { bool is_bridge() const {
return this->role == erBridgeInfill return this->m_role == erBridgeInfill
|| this->role == erOverhangPerimeter; || this->m_role == erOverhangPerimeter;
} }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // 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. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
@ -135,6 +138,8 @@ public:
private: private:
void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
ExtrusionRole m_role;
}; };
typedef std::vector<ExtrusionPath> ExtrusionPaths; typedef std::vector<ExtrusionPath> ExtrusionPaths;
@ -161,21 +166,22 @@ public:
Point first_point() const { return this->paths.front().polyline.points.front(); } Point first_point() const { return this->paths.front().polyline.points.front(); }
Point last_point() const { return this->paths.back().polyline.points.back(); } Point last_point() const { return this->paths.back().polyline.points.back(); }
virtual double length() const; virtual double length() const;
virtual ExtrusionRole role() const { return this->paths.empty() ? erNone : this->paths.front().role(); }
bool is_perimeter() const { bool is_perimeter() const {
return this->paths.front().role == erPerimeter return this->paths.front().role() == erPerimeter
|| this->paths.front().role == erExternalPerimeter || this->paths.front().role() == erExternalPerimeter
|| this->paths.front().role == erOverhangPerimeter; || this->paths.front().role() == erOverhangPerimeter;
} }
bool is_infill() const { bool is_infill() const {
return this->paths.front().role == erBridgeInfill return this->paths.front().role() == erBridgeInfill
|| this->paths.front().role == erInternalInfill || this->paths.front().role() == erInternalInfill
|| this->paths.front().role == erSolidInfill || this->paths.front().role() == erSolidInfill
|| this->paths.front().role == erTopSolidInfill; || this->paths.front().role() == erTopSolidInfill;
} }
bool is_solid_infill() const { bool is_solid_infill() const {
return this->paths.front().role == erBridgeInfill return this->paths.front().role() == erBridgeInfill
|| this->paths.front().role == erSolidInfill || this->paths.front().role() == erSolidInfill
|| this->paths.front().role == erTopSolidInfill; || this->paths.front().role() == erTopSolidInfill;
} }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // 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. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
@ -198,13 +204,12 @@ class ExtrusionLoop : public ExtrusionEntity
{ {
public: public:
ExtrusionPaths paths; 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) ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault)
: paths(paths), role(role) {}; : paths(paths), m_loop_role(role) {};
ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault)
: role(role) { : m_loop_role(role) {
this->paths.push_back(path); this->paths.push_back(path);
}; };
bool is_loop() const { return true; } bool is_loop() const { return true; }
@ -223,21 +228,23 @@ class ExtrusionLoop : public ExtrusionEntity
// Test, whether the point is extruded by a bridging flow. // 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. // 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; 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 { bool is_perimeter() const {
return this->paths.front().role == erPerimeter return this->paths.front().role() == erPerimeter
|| this->paths.front().role == erExternalPerimeter || this->paths.front().role() == erExternalPerimeter
|| this->paths.front().role == erOverhangPerimeter; || this->paths.front().role() == erOverhangPerimeter;
} }
bool is_infill() const { bool is_infill() const {
return this->paths.front().role == erBridgeInfill return this->paths.front().role() == erBridgeInfill
|| this->paths.front().role == erInternalInfill || this->paths.front().role() == erInternalInfill
|| this->paths.front().role == erSolidInfill || this->paths.front().role() == erSolidInfill
|| this->paths.front().role == erTopSolidInfill; || this->paths.front().role() == erTopSolidInfill;
} }
bool is_solid_infill() const { bool is_solid_infill() const {
return this->paths.front().role == erBridgeInfill return this->paths.front().role() == erBridgeInfill
|| this->paths.front().role == erSolidInfill || this->paths.front().role() == erSolidInfill
|| this->paths.front().role == erTopSolidInfill; || this->paths.front().role() == erTopSolidInfill;
} }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // 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. // 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. // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const; double min_mm3_per_mm() const;
Polyline as_polyline() const { return this->polygon().split_at_first_point(); } 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) inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)

View File

@ -81,22 +81,22 @@ ExtrusionEntityCollection::remove(size_t i)
} }
ExtrusionEntityCollection ExtrusionEntityCollection
ExtrusionEntityCollection::chained_path(bool no_reverse, std::vector<size_t>* orig_indices) const ExtrusionEntityCollection::chained_path(bool no_reverse, ExtrusionRole role) const
{ {
ExtrusionEntityCollection coll; ExtrusionEntityCollection coll;
this->chained_path(&coll, no_reverse, orig_indices); this->chained_path(&coll, no_reverse, role);
return coll; return coll;
} }
void void
ExtrusionEntityCollection::chained_path(ExtrusionEntityCollection* retval, bool no_reverse, std::vector<size_t>* orig_indices) const ExtrusionEntityCollection::chained_path(ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector<size_t>* orig_indices) const
{ {
if (this->entities.empty()) return; 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 void
ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse, std::vector<size_t>* orig_indices) const ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector<size_t>* orig_indices) const
{ {
if (this->no_sort) { if (this->no_sort) {
*retval = *this; *retval = *this;
@ -110,6 +110,15 @@ ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCo
ExtrusionEntitiesPtr my_paths; ExtrusionEntitiesPtr my_paths;
for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) { 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(); ExtrusionEntity* entity = (*it)->clone();
my_paths.push_back(entity); my_paths.push_back(entity);
if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin(); if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin();

View File

@ -24,6 +24,14 @@ public:
explicit operator ExtrusionPaths() const; explicit operator ExtrusionPaths() const;
bool is_collection() const { return true; }; 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 can_reverse() const { return !this->no_sort; };
bool empty() const { return this->entities.empty(); }; bool empty() const { return this->entities.empty(); };
void clear(); void clear();
@ -49,9 +57,9 @@ public:
} }
void replace(size_t i, const ExtrusionEntity &entity); void replace(size_t i, const ExtrusionEntity &entity);
void remove(size_t i); void remove(size_t i);
ExtrusionEntityCollection chained_path(bool no_reverse = false, std::vector<size_t>* orig_indices = NULL) const; ExtrusionEntityCollection chained_path(bool no_reverse = false, ExtrusionRole role = erMixed) const;
void chained_path(ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector<size_t>* orig_indices = NULL) const; void chained_path(ExtrusionEntityCollection* retval, bool no_reverse = false, ExtrusionRole role = erMixed, std::vector<size_t>* orig_indices = nullptr) const;
void chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector<size_t>* orig_indices = NULL) const; void chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse = false, ExtrusionRole role = erMixed, std::vector<size_t>* orig_indices = nullptr) const;
void reverse(); void reverse();
Point first_point() const { return this->entities.front()->first_point(); } Point first_point() const { return this->entities.front()->first_point(); }
Point last_point() const { return this->entities.back()->last_point(); } Point last_point() const { return this->entities.back()->last_point(); }

View File

@ -354,6 +354,7 @@ static inline const char* ExtrusionRole2String(const ExtrusionRole role)
case erSkirt: return "erSkirt"; case erSkirt: return "erSkirt";
case erSupportMaterial: return "erSupportMaterial"; case erSupportMaterial: return "erSupportMaterial";
case erSupportMaterialInterface: return "erSupportMaterialInterface"; case erSupportMaterialInterface: return "erSupportMaterialInterface";
case erMixed: return "erMixed";
default: return "erInvalid"; default: return "erInvalid";
}; };
} }
@ -565,7 +566,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
bool was_clockwise = loop.make_counter_clockwise(); bool was_clockwise = loop.make_counter_clockwise();
SeamPosition seam_position = this->config.seam_position; SeamPosition seam_position = this->config.seam_position;
if (loop.role == elrSkirt) if (loop.loop_role() == elrSkirt)
seam_position = spNearest; seam_position = spNearest;
// find the point of the loop that is closest to the current extruder position // 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); loop.split_at(polygon.points[idx_min], true);
} else if (seam_position == spRandom) { } 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. // 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 // The other loops will get a seam close to the random point chosen
// on the inner most contour. // on the inner most contour.
@ -750,7 +751,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
// extrude along the path // extrude along the path
std::string gcode; std::string gcode;
for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) { for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
// description += ExtrusionLoopRole2String(loop.role); // description += ExtrusionLoopRole2String(loop.loop_role());
// description += ExtrusionRole2String(path->role); // description += ExtrusionRole2String(path->role);
path->simplify(SCALED_RESOLUTION); path->simplify(SCALED_RESOLUTION);
gcode += this->_extrude(*path, description, speed); 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 this->wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path
// make a little move inwards before leaving loop // 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 // detect angle between last and first segment
// the side depends on the original winding order of the polygon (left for contours, right for holes) // 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 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 // extrude along the path
std::string gcode; std::string gcode;
for (ExtrusionPaths::iterator path = multipath.paths.begin(); path != multipath.paths.end(); ++path) { 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); // description += ExtrusionRole2String(path->role);
path->simplify(SCALED_RESOLUTION); path->simplify(SCALED_RESOLUTION);
gcode += this->_extrude(*path, description, speed); gcode += this->_extrude(*path, description, speed);
@ -837,7 +838,7 @@ GCode::extrude(const ExtrusionEntity &entity, std::string description, double sp
std::string std::string
GCode::extrude(ExtrusionPath path, std::string description, double speed) GCode::extrude(ExtrusionPath path, std::string description, double speed)
{ {
// description += ExtrusionRole2String(path.role); // description += ExtrusionRole2String(path.role());
path.simplify(SCALED_RESOLUTION); path.simplify(SCALED_RESOLUTION);
std::string gcode = this->_extrude(path, description, speed); std::string gcode = this->_extrude(path, description, speed);
if (this->wipe.enable) { if (this->wipe.enable) {
@ -849,6 +850,40 @@ GCode::extrude(ExtrusionPath path, std::string description, double speed)
return gcode; 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<const ExtrusionPath*>(ee);
if (path)
gcode += this->extrude(*path, label, speed);
else {
const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee);
assert(multipath != nullptr);
if (multipath)
gcode += this->extrude(*multipath, label, speed);
}
}
}
return gcode;
}
std::string std::string
GCode::_extrude(const ExtrusionPath &path, std::string description, double speed) 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())) { if (!this->_last_pos_defined || !this->_last_pos.coincides_with(path.first_point())) {
gcode += this->travel_to( gcode += this->travel_to(
path.first_point(), path.first_point(),
path.role, path.role(),
"move to first " + description + " point" "move to first " + description + " point"
); );
} }
@ -889,19 +924,19 @@ GCode::_extrude(const ExtrusionPath &path, std::string description, double speed
// set speed // set speed
if (speed == -1) { if (speed == -1) {
if (path.role == erPerimeter) { if (path.role() == erPerimeter) {
speed = this->config.get_abs_value("perimeter_speed"); 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"); 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"); 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"); 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"); 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"); 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"); speed = this->config.get_abs_value("gap_fill_speed");
} else { } else {
CONFESS("Invalid speed"); CONFESS("Invalid speed");
@ -931,10 +966,10 @@ GCode::_extrude(const ExtrusionPath &path, std::string description, double speed
// extrude arc or line // extrude arc or line
if (this->enable_extrusion_role_markers || this->enable_analyzer_markers) { if (this->enable_extrusion_role_markers || this->enable_analyzer_markers) {
if (path.role != this->_last_extrusion_role) { if (path.role() != this->_last_extrusion_role) {
this->_last_extrusion_role = path.role; this->_last_extrusion_role = path.role();
char buf[32]; char buf[32];
sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role)); sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role()));
gcode += buf; gcode += buf;
} }
} }

View File

@ -123,6 +123,7 @@ class GCode {
std::string extrude(ExtrusionLoop loop, std::string description = "", double speed = -1); 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(ExtrusionMultiPath multipath, std::string description = "", double speed = -1);
std::string extrude(ExtrusionPath path, 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); std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone); bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone);
std::string retract(bool toolchange = false); std::string retract(bool toolchange = false);

View File

@ -143,10 +143,8 @@ class SupportLayer : public Layer {
public: public:
// Polygons covered by the supports: base, interface and contact areas. // Polygons covered by the supports: base, interface and contact areas.
ExPolygonCollection support_islands; 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; ExtrusionEntityCollection support_fills;
// Extrusion paths for the support interface and contacts.
ExtrusionEntityCollection support_interface_fills;
protected: protected:
SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z,

View File

@ -391,7 +391,7 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
// sort entities into a new collection using a nearest-neighbor search, // sort entities into a new collection using a nearest-neighbor search,
// preserving the original indices which are useful for detecting thin walls // preserving the original indices which are useful for detecting thin walls
ExtrusionEntityCollection sorted_coll; 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 // traverse children and build the final collection
ExtrusionEntityCollection entities; ExtrusionEntityCollection entities;

View File

@ -903,8 +903,6 @@ void Print::_make_skirt()
break; break;
for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities) for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities)
append(object_points, extrusion_entity->as_polyline().points); 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. // Repeat points for each object copy.
for (const Point &shift : object->_shifted_copies) { for (const Point &shift : object->_shifted_copies) {

View File

@ -835,10 +835,8 @@ void _3DScene::_load_print_object_toolpaths(
} }
if (ctxt.has_support) { if (ctxt.has_support) {
const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer); const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(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_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) { for (size_t i = 0; i < 3; ++ i) {

View File

@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use Slic3r::XS; use Slic3r::XS;
use Test::More tests => 8; use Test::More tests => 7;
my $points = [ my $points = [
[100, 100], [100, 100],
@ -34,7 +34,5 @@ ok $path->first_point->coincides_with($path->polyline->[0]), 'first_point';
$path = $path->clone; $path = $path->clone;
is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; 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__ __END__

View File

@ -5,7 +5,7 @@ use warnings;
use List::Util qw(sum); use List::Util qw(sum);
use Slic3r::XS; use Slic3r::XS;
use Test::More tests => 48; use Test::More tests => 47;
{ {
my $square = [ my $square = [
@ -35,8 +35,6 @@ use Test::More tests => 48;
my $path = $loop->[0]; my $path = $loop->[0];
isa_ok $path, 'Slic3r::ExtrusionPath::Ref'; isa_ok $path, 'Slic3r::ExtrusionPath::Ref';
is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; 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]); $loop->split_at_vertex($square_p->[2]);

View File

@ -12,15 +12,15 @@
%code{% RETVAL = THIS->clone(); %}; %code{% RETVAL = THIS->clone(); %};
void reverse(); void reverse();
void clear(); void clear();
ExtrusionEntityCollection* chained_path(bool no_reverse) ExtrusionEntityCollection* chained_path(bool no_reverse, ExtrusionRole role = erMixed)
%code{% %code{%
RETVAL = new ExtrusionEntityCollection(); 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{% %code{%
RETVAL = new ExtrusionEntityCollection(); RETVAL = new ExtrusionEntityCollection();
THIS->chained_path_from(*start_near, RETVAL, no_reverse); THIS->chained_path_from(*start_near, RETVAL, no_reverse, role);
%}; %};
Clone<Point> first_point(); Clone<Point> first_point();
Clone<Point> last_point(); Clone<Point> last_point();
@ -100,13 +100,5 @@ ExtrusionEntityCollection::no_sort(...)
OUTPUT: OUTPUT:
RETVAL RETVAL
ExtrusionEntityCollection*
ExtrusionEntityCollection::chained_path_indices(bool no_reverse)
CODE:
RETVAL = new ExtrusionEntityCollection();
THIS->chained_path(RETVAL, no_reverse, &RETVAL->orig_indices);
OUTPUT:
RETVAL
%} %}
}; };

View File

@ -27,6 +27,8 @@
%code{% THIS->clip_end(distance, &RETVAL); %}; %code{% THIS->clip_end(distance, &RETVAL); %};
bool has_overhang_point(Point* point) bool has_overhang_point(Point* point)
%code{% RETVAL = THIS->has_overhang_point(*point); %}; %code{% RETVAL = THIS->has_overhang_point(*point); %};
ExtrusionRole role() const;
ExtrusionLoopRole loop_role() const;
bool is_perimeter(); bool is_perimeter();
bool is_infill(); bool is_infill();
bool is_solid_infill(); bool is_solid_infill();
@ -46,16 +48,6 @@ ExtrusionLoop::arrayref()
OUTPUT: OUTPUT:
RETVAL RETVAL
ExtrusionLoopRole
ExtrusionLoop::role(...)
CODE:
if (items > 1) {
THIS->role = (ExtrusionLoopRole)SvUV(ST(1));
}
RETVAL = THIS->role;
OUTPUT:
RETVAL
%} %}
}; };

View File

@ -22,6 +22,7 @@
void clip_end(double distance); void clip_end(double distance);
void simplify(double tolerance); void simplify(double tolerance);
double length(); double length();
ExtrusionRole role() const;
bool is_perimeter(); bool is_perimeter();
bool is_infill(); bool is_infill();
bool is_solid_infill(); bool is_solid_infill();
@ -57,16 +58,6 @@ ExtrusionPath::polyline(...)
OUTPUT: OUTPUT:
RETVAL RETVAL
ExtrusionRole
ExtrusionPath::role(...)
CODE:
if (items > 1) {
THIS->role = (ExtrusionRole)SvUV(ST(1));
}
RETVAL = THIS->role;
OUTPUT:
RETVAL
double double
ExtrusionPath::mm3_per_mm(...) ExtrusionPath::mm3_per_mm(...)
CODE: CODE:
@ -143,6 +134,7 @@ _constant()
EXTR_ROLE_SKIRT = erSkirt EXTR_ROLE_SKIRT = erSkirt
EXTR_ROLE_SUPPORTMATERIAL = erSupportMaterial EXTR_ROLE_SUPPORTMATERIAL = erSupportMaterial
EXTR_ROLE_SUPPORTMATERIAL_INTERFACE = erSupportMaterialInterface EXTR_ROLE_SUPPORTMATERIAL_INTERFACE = erSupportMaterialInterface
EXTR_ROLE_MIXED = erMixed
PROTOTYPE: PROTOTYPE:
CODE: CODE:
RETVAL = ix; RETVAL = ix;

View File

@ -181,6 +181,7 @@
%code{% RETVAL = THIS->extrude(*multipath, description, speed); %}; %code{% RETVAL = THIS->extrude(*multipath, description, speed); %};
%name{extrude_path} std::string extrude(ExtrusionPath* path, std::string description = "", double speed = -1) %name{extrude_path} std::string extrude(ExtrusionPath* path, std::string description = "", double speed = -1)
%code{% RETVAL = THIS->extrude(*path, description, speed); %}; %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) std::string travel_to(Point* point, ExtrusionRole role, std::string comment)
%code{% RETVAL = THIS->travel_to(*point, role, comment); %}; %code{% RETVAL = THIS->travel_to(*point, role, comment); %};
bool needs_retraction(Polyline* travel, ExtrusionRole role = erNone) bool needs_retraction(Polyline* travel, ExtrusionRole role = erNone)

View File

@ -110,9 +110,6 @@
%code%{ RETVAL = &THIS->support_islands; %}; %code%{ RETVAL = &THIS->support_islands; %};
Ref<ExtrusionEntityCollection> support_fills() Ref<ExtrusionEntityCollection> support_fills()
%code%{ RETVAL = &THIS->support_fills; %}; %code%{ RETVAL = &THIS->support_fills; %};
Ref<ExtrusionEntityCollection> support_interface_fills()
%code%{ RETVAL = &THIS->support_interface_fills; %};
// copies of some Layer methods, because the parameter wrapper code // copies of some Layer methods, because the parameter wrapper code
// gets confused about getting a Layer::Support instead of a Layer // gets confused about getting a Layer::Support instead of a Layer