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
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;

View File

@ -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);

View File

@ -1,5 +1,6 @@
#include "GCode.hpp"
#include "ExtrusionEntity.hpp"
#include <algorithm>
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);

View File

@ -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);

View File

@ -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)

View File

@ -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)