diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 14080cb17..2b50f8f9c 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -151,7 +151,7 @@ sub extrude_loop { } # extrude along the path - my $gcode = join '', map $self->_extrude_path($_, $description, $speed), @paths; + my $gcode = join '', map $self->_extrude_path($_, $description // "", $speed // -1), @paths; # reset acceleration $gcode .= $self->writer->set_acceleration($self->config->default_acceleration); @@ -185,115 +185,4 @@ sub extrude_loop { return $gcode; } -sub extrude_path { - my ($self, $path, $description, $speed) = @_; - - my $gcode = $self->_extrude_path($path, $description, $speed); - - # reset acceleration - $gcode .= $self->writer->set_acceleration($self->config->default_acceleration); - - return $gcode; -} - -sub _extrude_path { - my ($self, $path, $description, $speed) = @_; - - $path->simplify(&Slic3r::SCALED_RESOLUTION); - - # go to first point of extrusion path - my $gcode = ""; - { - my $first_point = $path->first_point; - $gcode .= $self->travel_to($first_point, $path->role, "move to first $description point") - if !$self->last_pos_defined || !$self->last_pos->coincides_with($first_point); - } - - # compensate retraction - $gcode .= $self->unretract; - - # adjust acceleration - { - my $acceleration; - if ($self->config->first_layer_acceleration && $self->first_layer) { - $acceleration = $self->config->first_layer_acceleration; - } elsif ($self->config->perimeter_acceleration && $path->is_perimeter) { - $acceleration = $self->config->perimeter_acceleration; - } elsif ($self->config->bridge_acceleration && $path->is_bridge) { - $acceleration = $self->config->bridge_acceleration; - } elsif ($self->config->infill_acceleration && $path->is_infill) { - $acceleration = $self->config->infill_acceleration; - } else { - $acceleration = $self->config->default_acceleration; - } - $gcode .= $self->writer->set_acceleration($acceleration); - } - - # calculate extrusion length per distance unit - my $e_per_mm = $self->writer->extruder->e_per_mm3 * $path->mm3_per_mm; - $e_per_mm = 0 if !$self->writer->extrusion_axis; - - # set speed - $speed //= -1; - if ($speed == -1) { - if ($path->role == EXTR_ROLE_PERIMETER) { - $speed = $self->config->get_abs_value('perimeter_speed'); - } elsif ($path->role == EXTR_ROLE_EXTERNAL_PERIMETER) { - $speed = $self->config->get_abs_value('external_perimeter_speed'); - } elsif ($path->role == EXTR_ROLE_OVERHANG_PERIMETER || $path->role == EXTR_ROLE_BRIDGE) { - $speed = $self->config->get_abs_value('bridge_speed'); - } elsif ($path->role == EXTR_ROLE_FILL) { - $speed = $self->config->get_abs_value('infill_speed'); - } elsif ($path->role == EXTR_ROLE_SOLIDFILL) { - $speed = $self->config->get_abs_value('solid_infill_speed'); - } elsif ($path->role == EXTR_ROLE_TOPSOLIDFILL) { - $speed = $self->config->get_abs_value('top_solid_infill_speed'); - } elsif ($path->role == EXTR_ROLE_GAPFILL) { - $speed = $self->config->get_abs_value('gap_fill_speed'); - } else { - die "Invalid speed"; - } - } - if ($self->first_layer) { - $speed = $self->config->get_abs_value_over('first_layer_speed', $speed); - } - if ($self->volumetric_speed != 0) { - $speed ||= $self->volumetric_speed / $path->mm3_per_mm; - } - if ($self->config->max_volumetric_speed > 0) { - # Cap speed with max_volumetric_speed anyway (even if user is not using autospeed) - $speed = min( - $speed, - $self->config->max_volumetric_speed / $path->mm3_per_mm, - ); - } - my $F = $speed * 60; # convert mm/sec to mm/min - - # extrude arc or line - $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge && $self->enable_cooling_markers; - my $path_length = unscale $path->length; - { - my $extruder_offset = $self->config->get_at('extruder_offset', $self->writer->extruder->id); - $gcode .= $path->gcode($self->writer->extruder, $e_per_mm, $F, - $self->origin->x - $extruder_offset->x, - $self->origin->y - $extruder_offset->y, #- - $self->writer->extrusion_axis, - $self->config->gcode_comments ? " ; $description" : ""); - - if ($self->wipe->enable) { - $self->wipe->set_path($path->polyline->clone); - $self->wipe->path->reverse; - } - } - $gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge && $self->enable_cooling_markers; - $self->set_last_pos($path->last_point); - - if ($self->config->cooling) { - my $path_time = $path_length / $F * 60; - $self->set_elapsed_time($self->elapsed_time + $path_time); - } - - return $gcode; -} - 1; diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index 4323e0965..c5d0f5fac 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -16,6 +16,7 @@ has '_second_layer_things_done' => (is => 'rw'); has '_last_obj_copy' => (is => 'rw'); use List::Util qw(first sum min max); +use Slic3r::ExtrusionPath ':roles'; use Slic3r::Flow ':roles'; use Slic3r::Geometry qw(X Y scale unscale chained_path convex_hull); use Slic3r::Geometry::Clipper qw(JT_SQUARE union_ex offset); @@ -251,7 +252,7 @@ sub export { print $fh $gcodegen->retract; print $fh $gcodegen->travel_to( Slic3r::Point->new(0,0), - undef, + EXTR_ROLE_NONE, 'move to origin position for next object', ); $gcodegen->set_enable_cooling_markers(1); diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 1c3a6dce0..5b5d26acd 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1,5 +1,6 @@ #include "GCode.hpp" #include "ExtrusionEntity.hpp" +#include namespace Slic3r { @@ -267,13 +268,126 @@ GCode::preamble() return gcode; } +std::string +GCode::extrude_path(const ExtrusionPath &path, std::string description, double speed) +{ + std::string gcode = this->_extrude_path(path, description, speed); + + // reset acceleration + gcode += this->writer.set_acceleration(this->config.default_acceleration.value); + + return gcode; +} + +std::string +GCode::_extrude_path(ExtrusionPath path, std::string description, double speed) +{ + path.simplify(SCALED_RESOLUTION); + + std::string gcode; + + // go to first point of extrusion path + if (!this->_last_pos_defined || !this->_last_pos.coincides_with(path.first_point())) { + gcode += this->travel_to( + path.first_point(), + path.role, + "move to first " + description + " point" + ); + } + + // compensate retraction + gcode += this->unretract(); + + // adjust acceleration + { + double acceleration; + if (this->config.first_layer_acceleration.value > 0 && this->first_layer) { + acceleration = this->config.first_layer_acceleration.value; + } else if (this->config.perimeter_acceleration.value > 0 && path.is_perimeter()) { + acceleration = this->config.perimeter_acceleration.value; + } else if (this->config.bridge_acceleration.value > 0 && path.is_bridge()) { + acceleration = this->config.bridge_acceleration.value; + } else if (this->config.infill_acceleration.value > 0 && path.is_infill()) { + acceleration = this->config.infill_acceleration.value; + } else { + acceleration = this->config.default_acceleration.value; + } + gcode += this->writer.set_acceleration(acceleration); + } + + // calculate extrusion length per distance unit + double e_per_mm = this->writer.extruder()->e_per_mm3 * path.mm3_per_mm; + if (this->writer.extrusion_axis().empty()) e_per_mm = 0; + + // set speed + if (speed == -1) { + if (path.role == erPerimeter) { + speed = this->config.get_abs_value("perimeter_speed"); + } else if (path.role == erExternalPerimeter) { + speed = this->config.get_abs_value("external_perimeter_speed"); + } else if (path.role == erOverhangPerimeter || path.role == erBridgeInfill) { + speed = this->config.get_abs_value("bridge_speed"); + } else if (path.role == erInternalInfill) { + speed = this->config.get_abs_value("infill_speed"); + } else if (path.role == erSolidInfill) { + speed = this->config.get_abs_value("solid_infill_speed"); + } else if (path.role == erTopSolidInfill) { + speed = this->config.get_abs_value("top_solid_infill_speed"); + } else if (path.role == erGapFill) { + speed = this->config.get_abs_value("gap_fill_speed"); + } else { + CONFESS("Invalid speed"); + } + } + if (this->first_layer) { + speed = this->config.get_abs_value("first_layer_speed", speed); + } + if (this->volumetric_speed != 0 && speed == 0) { + speed = this->volumetric_speed / path.mm3_per_mm; + } + if (this->config.max_volumetric_speed.value > 0) { + // cap speed with max_volumetric_speed anyway (even if user is not using autospeed) + speed = std::min( + speed, + this->config.max_volumetric_speed.value / path.mm3_per_mm + ); + } + double F = speed * 60; // convert mm/sec to mm/min + + // extrude arc or line + if (path.is_bridge() && this->enable_cooling_markers) + gcode += ";_BRIDGE_FAN_START\n"; + double path_length = unscale(path.length()); + { + Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset); + gcode += path.gcode(this->writer.extruder(), e_per_mm, F, + this->origin.x - extruder_offset.x, + this->origin.y - extruder_offset.y, + this->writer.extrusion_axis(), + this->config.gcode_comments ? (" ; " + description) : ""); + + if (this->wipe.enable) { + this->wipe.path = path.polyline; + this->wipe.path.reverse(); + } + } + if (path.is_bridge() && this->enable_cooling_markers) + gcode += ";_BRIDGE_FAN_END\n"; + this->set_last_pos(path.last_point()); + + if (this->config.cooling) + this->elapsed_time += path_length / F * 60; + + return gcode; +} + // This method accepts &point in print coordinates. std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string comment) { /* Define the travel move as a line between current position and the taget point. This is expressed in print coordinates, so it will need to be translated by - $self->origin in order to get G-code coordinates. */ + this->origin in order to get G-code coordinates. */ Polyline travel; travel.append(this->last_pos()); travel.append(point); diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index d71069c92..0af91b661 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -92,6 +92,8 @@ class GCode { void apply_print_config(const PrintConfig &print_config); void set_origin(const Pointf &pointf); std::string preamble(); + std::string extrude_path(const ExtrusionPath &path, std::string description = "", double speed = -1); + std::string _extrude_path(ExtrusionPath path, std::string description = "", double speed = -1); 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/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 965174959..470dbe015 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -10,6 +10,8 @@ #define EPSILON 1e-4 #define SCALING_FACTOR 0.000001 +#define RESOLUTION 0.0125 +#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR) #define PI 3.141592653589793238 #define scale_(val) (val / SCALING_FACTOR) #define unscale(val) (val * SCALING_FACTOR) diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp index 7595e829a..1aa1dfdad 100644 --- a/xs/xsp/GCode.xsp +++ b/xs/xsp/GCode.xsp @@ -157,6 +157,10 @@ void set_origin(Pointf* pointf) %code{% THIS->set_origin(*pointf); %}; std::string preamble(); + std::string extrude_path(ExtrusionPath* path, std::string description = "", double speed = -1) + %code{% RETVAL = THIS->extrude_path(*path, description, speed); %}; + std::string _extrude_path(ExtrusionPath* path, std::string description = "", double speed = -1) + %code{% RETVAL = THIS->_extrude_path(*path, description, speed); %}; 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)