Ported more Slic3r::GCode methods to XS

This commit is contained in:
Alessandro Ranellucci 2015-07-01 23:00:52 +02:00
parent 801f629fdc
commit b4019bb438
9 changed files with 237 additions and 165 deletions

View File

@ -8,13 +8,6 @@ use Slic3r::ExtrusionPath ':roles';
use Slic3r::Geometry qw(epsilon scale unscale PI X Y B); use Slic3r::Geometry qw(epsilon scale unscale PI X Y B);
use Slic3r::Geometry::Clipper qw(union_ex); use Slic3r::Geometry::Clipper qw(union_ex);
sub apply_print_config {
my ($self, $print_config) = @_;
$self->writer->apply_print_config($print_config);
$self->config->apply_print_config($print_config);
}
sub set_extruders { sub set_extruders {
my ($self, $extruder_ids) = @_; my ($self, $extruder_ids) = @_;
@ -24,34 +17,6 @@ sub set_extruders {
$self->wipe->set_enable(defined first { $self->config->get_at('wipe', $_) } @$extruder_ids); $self->wipe->set_enable(defined first { $self->config->get_at('wipe', $_) } @$extruder_ids);
} }
sub set_origin {
my ($self, $pointf) = @_;
# if origin increases (goes towards right), last_pos decreases because it goes towards left
my @translate = (
scale ($self->origin->x - $pointf->x),
scale ($self->origin->y - $pointf->y), #-
);
$self->last_pos->translate(@translate);
$self->wipe->path->translate(@translate) if $self->wipe->has_path;
$self->_set_origin($pointf);
}
sub preamble {
my ($self) = @_;
my $gcode = $self->writer->preamble;
# Perform a *silent* move to z_offset: we need this to initialize the Z
# position of our writer object so that any initial lift taking place
# before the first layer change will raise the extruder from the correct
# initial Z instead of 0.
$self->writer->travel_to_z($self->config->z_offset, '');
return $gcode;
}
sub change_layer { sub change_layer {
my ($self, $layer) = @_; my ($self, $layer) = @_;
@ -348,7 +313,7 @@ sub travel_to {
if ($needs_retraction if ($needs_retraction
&& $self->config->avoid_crossing_perimeters && $self->config->avoid_crossing_perimeters
&& !$self->avoid_crossing_perimeters->disable_once) { && !$self->avoid_crossing_perimeters->disable_once) {
$travel = $self->avoid_crossing_perimeters->travel_to($point, $self->origin, $self->last_pos); $travel = $self->avoid_crossing_perimeters->travel_to($self, $point);
# check again whether the new travel path still needs a retraction # check again whether the new travel path still needs a retraction
$needs_retraction = $self->needs_retraction($travel, $role); $needs_retraction = $self->needs_retraction($travel, $role);
@ -404,51 +369,6 @@ sub needs_retraction {
return 1; return 1;
} }
sub retract {
my ($self, $toolchange) = @_;
return "" if !defined $self->writer->extruder;
my $gcode = "";
# wipe (if it's enabled for this extruder and we have a stored wipe path)
if ($self->config->get_at('wipe', $self->writer->extruder->id) && $self->wipe->has_path) {
$gcode .= $self->wipe->wipe($self, $toolchange);
}
# The parent class will decide whether we need to perform an actual retraction
# (the extruder might be already retracted fully or partially). We call these
# methods even if we performed wipe, since this will ensure the entire retraction
# length is honored in case wipe path was too short.p
$gcode .= $toolchange ? $self->writer->retract_for_toolchange : $self->writer->retract;
$gcode .= $self->writer->reset_e;
$gcode .= $self->writer->lift
if $self->writer->extruder->retract_length > 0 || $self->config->use_firmware_retraction;
return $gcode;
}
sub unretract {
my ($self) = @_;
my $gcode = "";
$gcode .= $self->writer->unlift;
$gcode .= $self->writer->unretract;
return $gcode;
}
# convert a model-space scaled point into G-code coordinates
sub point_to_gcode {
my ($self, $point) = @_;
my $extruder_offset = $self->config->get_at('extruder_offset', $self->writer->extruder->id);
return Slic3r::Pointf->new(
($point->x * &Slic3r::SCALING_FACTOR) + $self->origin->x - $extruder_offset->x,
($point->y * &Slic3r::SCALING_FACTOR) + $self->origin->y - $extruder_offset->y, #**
);
}
sub set_extruder { sub set_extruder {
my ($self, $extruder_id) = @_; my ($self, $extruder_id) = @_;
@ -535,63 +455,4 @@ sub post_toolchange {
return $gcode; return $gcode;
} }
package Slic3r::GCode::Wipe;
use strict;
use warnings;
use Slic3r::Geometry qw(scale);
sub wipe {
my ($self, $gcodegen, $toolchange) = @_;
my $gcode = "";
# Reduce feedrate a bit; travel speed is often too high to move on existing material.
# Too fast = ripping of existing material; too slow = short wipe path, thus more blob.
my $wipe_speed = $gcodegen->writer->config->get('travel_speed') * 0.8;
# get the retraction length
my $length = $toolchange
? $gcodegen->writer->extruder->retract_length_toolchange
: $gcodegen->writer->extruder->retract_length;
if ($length) {
# Calculate how long we need to travel in order to consume the required
# amount of retraction. In other words, how far do we move in XY at $wipe_speed
# for the time needed to consume retract_length at retract_speed?
my $wipe_dist = scale($length / $gcodegen->writer->extruder->retract_speed * $wipe_speed);
# Take the stored wipe path and replace first point with the current actual position
# (they might be different, for example, in case of loop clipping).
my $wipe_path = Slic3r::Polyline->new(
$gcodegen->last_pos,
@{$self->path}[1..$#{$self->path}],
);
#
$wipe_path->clip_end($wipe_path->length - $wipe_dist);
# subdivide the retraction in segments
my $retracted = 0;
foreach my $line (@{$wipe_path->lines}) {
my $segment_length = $line->length;
# Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
# due to rounding (TODO: test and/or better math for this)
my $dE = $length * ($segment_length / $wipe_dist) * 0.95;
$gcode .= $gcodegen->writer->set_speed($wipe_speed*60);
$gcode .= $gcodegen->writer->extrude_to_xy(
$gcodegen->point_to_gcode($line->b),
-$dE,
'wipe and retract' . ($gcodegen->enable_cooling_markers ? ';_WIPE' : ''),
);
$retracted += $dE;
}
$gcodegen->writer->extruder->set_retracted($gcodegen->writer->extruder->retracted + $retracted);
# prevent wiping again on same path
$self->reset_path;
}
return $gcode;
}
1; 1;

View File

@ -192,7 +192,7 @@ use Slic3r::Test;
push @z_steps, $info->{dist_Z} push @z_steps, $info->{dist_Z}
if $started_extruding && $info->{dist_Z} > 0; if $started_extruding && $info->{dist_Z} > 0;
$travel_moves_after_first_extrusion++ $travel_moves_after_first_extrusion++
if $info->{travel} && $started_extruding && !exists $args->{Z}; if $info->{travel} && $info->{dist_XY} > 0 && $started_extruding && !exists $args->{Z};
} elsif ($cmd eq 'M104') { } elsif ($cmd eq 'M104') {
$first_layer_temperature_set = 1 if $args->{S} == 205; $first_layer_temperature_set = 1 if $args->{S} == 205;
$temperature_set = 1 if $args->{S} == 200; $temperature_set = 1 if $args->{S} == 200;
@ -271,7 +271,7 @@ use Slic3r::Test;
foreach my $segment (@this_layer) { foreach my $segment (@this_layer) {
# check that segment's dist_Z is proportioned to its dist_XY # check that segment's dist_Z is proportioned to its dist_XY
$all_layer_segments_have_same_slope = 1 $all_layer_segments_have_same_slope = 1
if abs($segment->[0]*$total_dist_XY/$config->layer_height - $segment->[1]) > 0.1; if abs($segment->[0]*$total_dist_XY/$config->layer_height - $segment->[1]) > 0.2;
} }
@this_layer = (); @this_layer = ();

View File

@ -1752,6 +1752,7 @@ t/17_boundingbox.t
t/18_motionplanner.t t/18_motionplanner.t
t/19_model.t t/19_model.t
t/20_print.t t/20_print.t
t/21_gcode.t
xsp/BoundingBox.xsp xsp/BoundingBox.xsp
xsp/BridgeDetector.xsp xsp/BridgeDetector.xsp
xsp/Clipper.xsp xsp/Clipper.xsp

View File

@ -36,16 +36,15 @@ AvoidCrossingPerimeters::init_layer_mp(const ExPolygons &islands)
} }
Polyline Polyline
AvoidCrossingPerimeters::travel_to(Point point, const Pointf &gcodegen_origin, AvoidCrossingPerimeters::travel_to(GCode &gcodegen, Point point)
const Point &gcodegen_last_pos)
{ {
if (this->use_external_mp || this->use_external_mp_once) { if (this->use_external_mp || this->use_external_mp_once) {
// get current origin set in gcodegen // get current origin set in gcodegen
// (the one that will be used to translate the G-code coordinates by) // (the one that will be used to translate the G-code coordinates by)
Point scaled_origin = Point::new_scale(gcodegen_origin.x, gcodegen_origin.y); Point scaled_origin = Point::new_scale(gcodegen.origin.x, gcodegen.origin.y);
// represent last_pos in absolute G-code coordinates // represent last_pos in absolute G-code coordinates
Point last_pos = gcodegen_last_pos; Point last_pos = gcodegen.last_pos();
last_pos.translate(scaled_origin); last_pos.translate(scaled_origin);
// represent point in absolute G-code coordinates // represent point in absolute G-code coordinates
@ -59,7 +58,7 @@ AvoidCrossingPerimeters::travel_to(Point point, const Pointf &gcodegen_origin,
travel.translate(scaled_origin.negative()); travel.translate(scaled_origin.negative());
return travel; return travel;
} else { } else {
return this->_layer_mp->shortest_path(gcodegen_last_pos, point); return this->_layer_mp->shortest_path(gcodegen.last_pos(), point);
} }
} }
@ -93,6 +92,62 @@ Wipe::reset_path()
this->path = Polyline(); this->path = Polyline();
} }
std::string
Wipe::wipe(GCode &gcodegen, bool toolchange)
{
std::string gcode;
/* Reduce feedrate a bit; travel speed is often too high to move on existing material.
Too fast = ripping of existing material; too slow = short wipe path, thus more blob. */
double wipe_speed = gcodegen.writer.config.travel_speed.value * 0.8;
// get the retraction length
double length = toolchange
? gcodegen.writer.extruder()->retract_length_toolchange()
: gcodegen.writer.extruder()->retract_length();
if (length > 0) {
/* Calculate how long we need to travel in order to consume the required
amount of retraction. In other words, how far do we move in XY at wipe_speed
for the time needed to consume retract_length at retract_speed? */
double wipe_dist = scale_(length / gcodegen.writer.extruder()->retract_speed() * wipe_speed);
/* Take the stored wipe path and replace first point with the current actual position
(they might be different, for example, in case of loop clipping). */
Polyline wipe_path;
wipe_path.append(gcodegen.last_pos());
wipe_path.append(
this->path.points.begin() + 1,
this->path.points.end()
);
wipe_path.clip_end(wipe_path.length() - wipe_dist);
// subdivide the retraction in segments
double retracted = 0;
Lines lines = wipe_path.lines();
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
double segment_length = line->length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
due to rounding (TODO: test and/or better math for this) */
double dE = length * (segment_length / wipe_dist) * 0.95;
gcode += gcodegen.writer.set_speed(wipe_speed*60);
gcode += gcodegen.writer.extrude_to_xy(
gcodegen.point_to_gcode(line->b),
-dE,
(std::string)"wipe and retract" + (gcodegen.enable_cooling_markers ? ";_WIPE" : "")
);
retracted += dE;
}
gcodegen.writer.extruder()->retracted += retracted;
// prevent wiping again on same path
this->reset_path();
}
return gcode;
}
#ifdef SLIC3RXS #ifdef SLIC3RXS
REGISTER_CLASS(Wipe, "GCode::Wipe"); REGISTER_CLASS(Wipe, "GCode::Wipe");
#endif #endif
@ -100,10 +155,110 @@ REGISTER_CLASS(Wipe, "GCode::Wipe");
GCode::GCode() GCode::GCode()
: enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0), : enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0),
layer_index(-1), first_layer(false), elapsed_time(0), volumetric_speed(0), layer_index(-1), first_layer(false), elapsed_time(0), volumetric_speed(0),
last_pos_defined(false) _last_pos_defined(false)
{ {
} }
Point&
GCode::last_pos()
{
return this->_last_pos;
}
void
GCode::set_last_pos(const Point &pos)
{
this->_last_pos = pos;
this->_last_pos_defined = true;
}
bool
GCode::last_pos_defined() const
{
return this->_last_pos_defined;
}
void
GCode::apply_print_config(const PrintConfig &print_config)
{
this->writer.apply_print_config(print_config);
this->config.apply(print_config);
}
void
GCode::set_origin(const Pointf &pointf)
{
// if origin increases (goes towards right), last_pos decreases because it goes towards left
Point translate(
scale_(this->origin.x - pointf.x),
scale_(this->origin.y - pointf.y)
);
this->_last_pos.translate(translate);
this->wipe.path.translate(translate);
this->origin = pointf;
}
std::string
GCode::preamble()
{
std::string gcode = this->writer.preamble();
/* Perform a *silent* move to z_offset: we need this to initialize the Z
position of our writer object so that any initial lift taking place
before the first layer change will raise the extruder from the correct
initial Z instead of 0. */
this->writer.travel_to_z(this->config.z_offset.value);
return gcode;
}
std::string
GCode::retract(bool toolchange)
{
std::string gcode;
if (this->writer.extruder() == NULL)
return gcode;
// wipe (if it's enabled for this extruder and we have a stored wipe path)
if (this->config.wipe.get_at(this->writer.extruder()->id) && this->wipe.has_path()) {
gcode += this->wipe.wipe(*this, toolchange);
}
/* The parent class will decide whether we need to perform an actual retraction
(the extruder might be already retracted fully or partially). We call these
methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */
gcode += toolchange ? this->writer.retract_for_toolchange() : this->writer.retract();
gcode += this->writer.reset_e();
if (this->writer.extruder()->retract_length() > 0 || this->config.use_firmware_retraction)
gcode += this->writer.lift();
return gcode;
}
std::string
GCode::unretract()
{
std::string gcode;
gcode += this->writer.unlift();
gcode += this->writer.unretract();
return gcode;
}
// convert a model-space scaled point into G-code coordinates
Pointf
GCode::point_to_gcode(const Point &point)
{
Pointf extruder_offset = this->config.extruder_offset.get_at(this->writer.extruder()->id);
return Pointf(
unscale(point.x) + this->origin.x - extruder_offset.x,
unscale(point.y) + this->origin.y - extruder_offset.y
);
}
#ifdef SLIC3RXS #ifdef SLIC3RXS
REGISTER_CLASS(GCode, "GCode"); REGISTER_CLASS(GCode, "GCode");
#endif #endif

View File

@ -14,7 +14,7 @@
namespace Slic3r { namespace Slic3r {
// draft for a binary representation of a G-code line class GCode;
class AvoidCrossingPerimeters { class AvoidCrossingPerimeters {
public: public:
@ -31,10 +31,7 @@ class AvoidCrossingPerimeters {
~AvoidCrossingPerimeters(); ~AvoidCrossingPerimeters();
void init_external_mp(const ExPolygons &islands); void init_external_mp(const ExPolygons &islands);
void init_layer_mp(const ExPolygons &islands); void init_layer_mp(const ExPolygons &islands);
Polyline travel_to(GCode &gcodegen, Point point);
//Polyline travel_to(GCode &gcodegen, const Point &point);
Polyline travel_to(Point point, const Pointf &gcodegen_origin,
const Point &gcodegen_last_pos);
private: private:
MotionPlanner* _external_mp; MotionPlanner* _external_mp;
@ -57,7 +54,7 @@ class Wipe {
Wipe(); Wipe();
bool has_path(); bool has_path();
void reset_path(); void reset_path();
//std::string wipe(GCode &gcodegen, bool toolchange = false); std::string wipe(GCode &gcodegen, bool toolchange = false);
}; };
class GCode { class GCode {
@ -81,11 +78,22 @@ class GCode {
std::map<PrintObject*,Point> _seam_position; std::map<PrintObject*,Point> _seam_position;
bool first_layer; // this flag triggers first layer speeds bool first_layer; // this flag triggers first layer speeds
unsigned int elapsed_time; // seconds unsigned int elapsed_time; // seconds
Point last_pos;
bool last_pos_defined;
double volumetric_speed; double volumetric_speed;
GCode(); GCode();
Point& last_pos();
void set_last_pos(const Point &pos);
bool last_pos_defined() const;
void apply_print_config(const PrintConfig &print_config);
void set_origin(const Pointf &pointf);
std::string preamble();
std::string retract(bool toolchange = false);
std::string unretract();
Pointf point_to_gcode(const Point &point);
private:
Point _last_pos;
bool _last_pos_defined;
}; };
} }

View File

@ -100,6 +100,24 @@ MultiPoint::remove_duplicate_points()
} }
} }
void
MultiPoint::append(const Point &point)
{
this->points.push_back(point);
}
void
MultiPoint::append(const Points &points)
{
this->append(points.begin(), points.end());
}
void
MultiPoint::append(const Points::const_iterator &begin, const Points::const_iterator &end)
{
this->points.insert(this->points.end(), begin, end);
}
Points Points
MultiPoint::_douglas_peucker(const Points &points, const double tolerance) MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
{ {

View File

@ -33,6 +33,9 @@ class MultiPoint
bool has_boundary_point(const Point &point) const; bool has_boundary_point(const Point &point) const;
BoundingBox bounding_box() const; BoundingBox bounding_box() const;
void remove_duplicate_points(); void remove_duplicate_points();
void append(const Point &point);
void append(const Points &points);
void append(const Points::const_iterator &begin, const Points::const_iterator &end);
static Points _douglas_peucker(const Points &points, const double tolerance); static Points _douglas_peucker(const Points &points, const double tolerance);

17
xs/t/21_gcode.t Normal file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
use strict;
use warnings;
use Slic3r::XS;
use Test::More tests => 2;
{
my $gcodegen = Slic3r::GCode->new;
$gcodegen->set_origin(Slic3r::Pointf->new(10,0));
is_deeply $gcodegen->origin->pp, [10,0], 'set_origin';
$gcodegen->origin->translate(5,5);
is_deeply $gcodegen->origin->pp, [15,5], 'origin returns reference to point';
}
__END__

View File

@ -11,8 +11,8 @@
void init_external_mp(ExPolygons islands); void init_external_mp(ExPolygons islands);
void init_layer_mp(ExPolygons islands); void init_layer_mp(ExPolygons islands);
Clone<Polyline> travel_to(Point* point, Pointf* gcodegen_origin, Point* gcodegen_last_pos) Clone<Polyline> travel_to(GCode* gcode, Point* point)
%code{% RETVAL = THIS->travel_to(*point, *gcodegen_origin, *gcodegen_last_pos); %}; %code{% RETVAL = THIS->travel_to(*gcode, *point); %};
bool use_external_mp() bool use_external_mp()
%code{% RETVAL = THIS->use_external_mp; %}; %code{% RETVAL = THIS->use_external_mp; %};
@ -51,6 +51,8 @@
bool has_path(); bool has_path();
void reset_path(); void reset_path();
std::string wipe(GCode* gcodegen, bool toolchange = false)
%code{% RETVAL = THIS->wipe(*gcodegen, toolchange); %};
bool enable() bool enable()
%code{% RETVAL = THIS->enable; %}; %code{% RETVAL = THIS->enable; %};
@ -69,8 +71,6 @@
Ref<Pointf> origin() Ref<Pointf> origin()
%code{% RETVAL = &(THIS->origin); %}; %code{% RETVAL = &(THIS->origin); %};
void _set_origin(Pointf* value)
%code{% THIS->origin = *value; %};
Ref<FullPrintConfig> config() Ref<FullPrintConfig> config()
%code{% RETVAL = &(THIS->config); %}; %code{% RETVAL = &(THIS->config); %};
@ -136,15 +136,24 @@
void set_elapsed_time(unsigned int value) void set_elapsed_time(unsigned int value)
%code{% THIS->elapsed_time = value; %}; %code{% THIS->elapsed_time = value; %};
bool last_pos_defined() bool last_pos_defined();
%code{% RETVAL = THIS->last_pos_defined; %};
Ref<Point> last_pos() Ref<Point> last_pos()
%code{% RETVAL = &(THIS->last_pos); %}; %code{% RETVAL = &(THIS->last_pos()); %};
void set_last_pos(Point* value) void set_last_pos(Point* pos)
%code{% THIS->last_pos = *value; THIS->last_pos_defined = true; %}; %code{% THIS->set_last_pos(*pos); %};
double volumetric_speed() double volumetric_speed()
%code{% RETVAL = THIS->volumetric_speed; %}; %code{% RETVAL = THIS->volumetric_speed; %};
void set_volumetric_speed(double value) void set_volumetric_speed(double value)
%code{% THIS->volumetric_speed = value; %}; %code{% THIS->volumetric_speed = value; %};
void apply_print_config(PrintConfig* print_config)
%code{% THIS->apply_print_config(*print_config); %};
void set_origin(Pointf* pointf)
%code{% THIS->set_origin(*pointf); %};
std::string preamble();
std::string retract(bool toolchange = false);
std::string unretract();
Clone<Pointf> point_to_gcode(Point* point)
%code{% RETVAL = THIS->point_to_gcode(*point); %};
}; };