Ported GCode::extrude_path() to XS (speed boost!)

This commit is contained in:
Alessandro Ranellucci 2015-07-02 18:57:40 +02:00
parent b025efe729
commit fbd640fdc5
6 changed files with 126 additions and 114 deletions

View File

@ -151,7 +151,7 @@ sub extrude_loop {
} }
# extrude along the path # 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 # reset acceleration
$gcode .= $self->writer->set_acceleration($self->config->default_acceleration); $gcode .= $self->writer->set_acceleration($self->config->default_acceleration);
@ -185,115 +185,4 @@ sub extrude_loop {
return $gcode; 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; 1;

View File

@ -16,6 +16,7 @@ has '_second_layer_things_done' => (is => 'rw');
has '_last_obj_copy' => (is => 'rw'); has '_last_obj_copy' => (is => 'rw');
use List::Util qw(first sum min max); use List::Util qw(first sum min max);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles'; use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(X Y scale unscale chained_path convex_hull); use Slic3r::Geometry qw(X Y scale unscale chained_path convex_hull);
use Slic3r::Geometry::Clipper qw(JT_SQUARE union_ex offset); use Slic3r::Geometry::Clipper qw(JT_SQUARE union_ex offset);
@ -251,7 +252,7 @@ sub export {
print $fh $gcodegen->retract; print $fh $gcodegen->retract;
print $fh $gcodegen->travel_to( print $fh $gcodegen->travel_to(
Slic3r::Point->new(0,0), Slic3r::Point->new(0,0),
undef, EXTR_ROLE_NONE,
'move to origin position for next object', 'move to origin position for next object',
); );
$gcodegen->set_enable_cooling_markers(1); $gcodegen->set_enable_cooling_markers(1);

View File

@ -1,5 +1,6 @@
#include "GCode.hpp" #include "GCode.hpp"
#include "ExtrusionEntity.hpp" #include "ExtrusionEntity.hpp"
#include <algorithm>
namespace Slic3r { namespace Slic3r {
@ -267,13 +268,126 @@ GCode::preamble()
return gcode; 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. // This method accepts &point in print coordinates.
std::string std::string
GCode::travel_to(const Point &point, ExtrusionRole role, std::string comment) 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. /* 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 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; Polyline travel;
travel.append(this->last_pos()); travel.append(this->last_pos());
travel.append(point); travel.append(point);

View File

@ -92,6 +92,8 @@ class GCode {
void apply_print_config(const PrintConfig &print_config); void apply_print_config(const PrintConfig &print_config);
void set_origin(const Pointf &pointf); void set_origin(const Pointf &pointf);
std::string preamble(); 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); 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

@ -10,6 +10,8 @@
#define EPSILON 1e-4 #define EPSILON 1e-4
#define SCALING_FACTOR 0.000001 #define SCALING_FACTOR 0.000001
#define RESOLUTION 0.0125
#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
#define PI 3.141592653589793238 #define PI 3.141592653589793238
#define scale_(val) (val / SCALING_FACTOR) #define scale_(val) (val / SCALING_FACTOR)
#define unscale(val) (val * SCALING_FACTOR) #define unscale(val) (val * SCALING_FACTOR)

View File

@ -157,6 +157,10 @@
void set_origin(Pointf* pointf) void set_origin(Pointf* pointf)
%code{% THIS->set_origin(*pointf); %}; %code{% THIS->set_origin(*pointf); %};
std::string preamble(); 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) 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)