Ported Slic3r::GCode storage to XS

This commit is contained in:
Alessandro Ranellucci 2015-07-01 21:47:17 +02:00
parent ab858f320d
commit 801f629fdc
13 changed files with 199 additions and 64 deletions

View File

@ -194,6 +194,7 @@ sub thread_cleanup {
*Slic3r::ExtrusionPath::DESTROY = sub {};
*Slic3r::ExtrusionPath::Collection::DESTROY = sub {};
*Slic3r::Flow::DESTROY = sub {};
*Slic3r::GCode::DESTROY = sub {};
*Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {};
*Slic3r::GCode::OozePrevention::DESTROY = sub {};
*Slic3r::GCode::PlaceholderParser::DESTROY = sub {};

View File

@ -1,5 +1,6 @@
package Slic3r::GCode;
use Moo;
use strict;
use warnings;
use List::Util qw(min max first);
use Slic3r::ExtrusionLoop ':roles';
@ -7,28 +8,6 @@ use Slic3r::ExtrusionPath ':roles';
use Slic3r::Geometry qw(epsilon scale unscale PI X Y B);
use Slic3r::Geometry::Clipper qw(union_ex);
# Origin of print coordinates expressed in unscaled G-code coordinates.
# This affects the input arguments supplied to the extrude*() and travel_to()
# methods.
has 'origin' => (is => 'rw', default => sub { Slic3r::Pointf->new });
has 'config' => (is => 'ro', default => sub { Slic3r::Config::Full->new });
has 'writer' => (is => 'ro', default => sub { Slic3r::GCode::Writer->new });
has 'placeholder_parser' => (is => 'rw', default => sub { Slic3r::GCode::PlaceholderParser->new });
has 'ooze_prevention' => (is => 'rw', default => sub { Slic3r::GCode::OozePrevention->new });
has 'wipe' => (is => 'rw', default => sub { Slic3r::GCode::Wipe->new });
has 'avoid_crossing_perimeters' => (is => 'rw', default => sub { Slic3r::GCode::AvoidCrossingPerimeters->new });
has 'enable_loop_clipping' => (is => 'rw', default => sub {1});
has 'enable_cooling_markers' => (is =>'rw', default => sub {0});
has 'layer_count' => (is => 'ro');
has 'layer_index' => (is => 'rw', default => sub {-1}); # just a counter
has 'layer' => (is => 'rw');
has '_seam_position' => (is => 'ro', default => sub { {} }); # $object => pos
has 'first_layer' => (is => 'rw', default => sub {0}); # this flag triggers first layer speeds
has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds
has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } );
has 'volumetric_speed' => (is => 'rw', default => sub {0});
sub apply_print_config {
my ($self, $print_config) = @_;
@ -56,7 +35,7 @@ sub set_origin {
$self->last_pos->translate(@translate);
$self->wipe->path->translate(@translate) if $self->wipe->has_path;
$self->origin($pointf);
$self->_set_origin($pointf);
}
sub preamble {
@ -76,9 +55,14 @@ sub preamble {
sub change_layer {
my ($self, $layer) = @_;
$self->layer($layer);
$self->layer_index($self->layer_index + 1);
$self->first_layer($layer->id == 0);
{
my $l = $layer->isa('Slic3r::Layer::Support')
? $layer->as_layer
: $layer;
$self->set_layer($l);
}
$self->set_layer_index($self->layer_index + 1);
$self->set_first_layer($layer->id == 0);
# avoid computing islands and overhangs if they're not needed
if ($self->config->avoid_crossing_perimeters) {
@ -88,7 +72,7 @@ sub change_layer {
}
my $gcode = "";
if (defined $self->layer_count) {
if ($self->layer_count > 0) {
$gcode .= $self->writer->update_progress($self->layer_index, $self->layer_count);
}
@ -146,11 +130,9 @@ sub extrude_loop {
@candidates = map @{$_->convex_points(PI*2/3)}, @simplified if !@candidates;
# retrieve the last start position for this object
my $obj_ptr = 0;
if (defined $self->layer) {
$obj_ptr = $self->layer->object->ptr;
if (defined $self->_seam_position->{$obj_ptr}) {
$last_pos = $self->_seam_position->{$obj_ptr};
if ($self->has_layer) {
if ($self->_has_seam_position($self->layer->object)) {
$last_pos = $self->_seam_position($self->layer->object);
}
}
@ -175,7 +157,8 @@ sub extrude_loop {
$point = $last_pos->projection_onto_polygon($polygon);
$loop->split_at($point);
}
$self->_seam_position->{$obj_ptr} = $point;
$self->_set_seam_position($self->layer->object, $point)
if $self->has_layer;
} elsif ($self->config->seam_position eq 'random') {
if ($loop->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER) {
my $polygon = $loop->polygon;
@ -211,7 +194,7 @@ sub extrude_loop {
$self->wipe->set_path($paths[0]->polyline->clone) if $self->wipe->enable; # TODO: don't limit wipe to last path
# make a little move inwards before leaving loop
if ($paths[-1]->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->config->perimeters > 1) {
if ($paths[-1]->role == EXTR_ROLE_EXTERNAL_PERIMETER && $self->has_layer && $self->config->perimeters > 1) {
my $last_path_polyline = $paths[-1]->polyline;
# detect angle between last and first segment
# the side depends on the original winding order of the polygon (left for contours, right for holes)
@ -258,7 +241,7 @@ sub _extrude_path {
{
my $first_point = $path->first_point;
$gcode .= $self->travel_to($first_point, $path->role, "move to first $description point")
if !defined $self->last_pos || !$self->last_pos->coincides_with($first_point);
if !$self->last_pos_defined || !$self->last_pos->coincides_with($first_point);
}
# compensate retraction
@ -338,11 +321,11 @@ sub _extrude_path {
}
}
$gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge && $self->enable_cooling_markers;
$self->last_pos($path->last_point);
$self->set_last_pos($path->last_point);
if ($self->config->cooling) {
my $path_time = $path_length / $F * 60;
$self->elapsed_time($self->elapsed_time + $path_time);
$self->set_elapsed_time($self->elapsed_time + $path_time);
}
return $gcode;
@ -394,12 +377,12 @@ sub needs_retraction {
return 0;
}
if (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands->contains_polyline($travel)) {
if (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->as_support_layer->support_islands->contains_polyline($travel)) {
# skip retraction if this is a travel move inside a support material island
return 0;
}
if ($self->config->only_retract_when_crossing_perimeters && defined $self->layer) {
if ($self->config->only_retract_when_crossing_perimeters && $self->has_layer) {
if ($self->config->fill_density > 0
&& $self->layer->any_internal_region_slice_contains_polyline($travel)) {
# skip retraction if travel is contained in an internal slice *and*
@ -527,7 +510,7 @@ sub pre_toolchange {
}
if ($gcodegen->config->standby_temperature_delta != 0) {
my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0
my $temp = $gcodegen->has_layer && $gcodegen->layer->id == 0
? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id)
: $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id);
# we assume that heating is always slower than cooling, so no need to block
@ -543,7 +526,7 @@ sub post_toolchange {
my $gcode = "";
if ($gcodegen->config->standby_temperature_delta != 0) {
my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0
my $temp = $gcodegen->has_layer && $gcodegen->layer->id == 0
? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id)
: $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id);
$gcode .= $gcodegen->writer->set_temperature($temp, 1);

View File

@ -27,7 +27,7 @@ sub append {
$self->last_z->{$obj_id} = $print_z;
$self->gcode($self->gcode . $gcode);
$self->elapsed_time($self->elapsed_time + $self->gcodegen->elapsed_time);
$self->gcodegen->elapsed_time(0);
$self->gcodegen->set_elapsed_time(0);
return $return;
}

View File

@ -35,12 +35,11 @@ sub BUILD {
}
# set up our helper object
my $gcodegen = Slic3r::GCode->new(
placeholder_parser => $self->placeholder_parser,
layer_count => $layer_count,
enable_cooling_markers => 1,
);
my $gcodegen = Slic3r::GCode->new;
$self->_gcodegen($gcodegen);
$gcodegen->set_placeholder_parser($self->placeholder_parser);
$gcodegen->set_layer_count($layer_count);
$gcodegen->set_enable_cooling_markers(1);
$gcodegen->apply_print_config($self->config);
$gcodegen->set_extruders($self->print->extruders);
@ -92,7 +91,7 @@ sub BUILD {
$self->config->max_volumetric_speed,
);
}
$gcodegen->volumetric_speed($volumetric_speed);
$gcodegen->set_volumetric_speed($volumetric_speed);
}
}
}
@ -247,7 +246,7 @@ sub export {
# no collision happens hopefully.
if ($finished_objects > 0) {
$gcodegen->set_origin(Slic3r::Pointf->new(map unscale $copy->[$_], X,Y));
$gcodegen->enable_cooling_markers(0); # we're not filtering these moves through CoolingBuffer
$gcodegen->set_enable_cooling_markers(0); # we're not filtering these moves through CoolingBuffer
$gcodegen->avoid_crossing_perimeters->set_use_external_mp_once(1);
print $fh $gcodegen->retract;
print $fh $gcodegen->travel_to(
@ -255,7 +254,7 @@ sub export {
undef,
'move to origin position for next object',
);
$gcodegen->enable_cooling_markers(1);
$gcodegen->set_enable_cooling_markers(1);
# disable motion planner when traveling to first object point
$gcodegen->avoid_crossing_perimeters->set_disable_once(1);
@ -364,7 +363,7 @@ sub process_layer {
}
# if we're going to apply spiralvase to this layer, disable loop clipping
$self->_gcodegen->enable_loop_clipping(!defined $self->_spiral_vase || !$self->_spiral_vase->enable);
$self->_gcodegen->set_enable_loop_clipping(!defined $self->_spiral_vase || !$self->_spiral_vase->enable);
if (!$self->_second_layer_things_done && $layer->id == 1) {
for my $extruder (@{$self->_gcodegen->writer->extruders}) {

View File

@ -18,9 +18,12 @@ sub buffer {
my $print_config = Slic3r::Config::Print->new;
$print_config->apply_dynamic($config);
my $gcodegen = Slic3r::GCode->new;
$gcodegen->apply_print_config($print_config);
$gcodegen->set_layer_count(10);
my $buffer = Slic3r::GCode::CoolingBuffer->new(
config => $print_config,
gcodegen => Slic3r::GCode->new(print_config => $print_config, layer_count => 10, extruders => []),
gcodegen => $gcodegen,
);
return $buffer;
}
@ -30,14 +33,14 @@ $config->set('disable_fan_first_layers', 0);
{
my $buffer = buffer($config);
$buffer->gcodegen->elapsed_time($buffer->config->slowdown_below_layer_time + 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->slowdown_below_layer_time + 1);
my $gcode = $buffer->append('G1 X100 E1 F3000', 0, 0, 0.4) . $buffer->flush;
like $gcode, qr/F3000/, 'speed is not altered when elapsed time is greater than slowdown threshold';
}
{
my $buffer = buffer($config);
$buffer->gcodegen->elapsed_time($buffer->config->slowdown_below_layer_time - 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->slowdown_below_layer_time - 1);
my $gcode = $buffer->append("G1 X50 F2500\nG1 X100 E1 F3000\nG1 E4 F400", 0, 0, 0.4) . $buffer->flush;
unlike $gcode, qr/F3000/, 'speed is altered when elapsed time is lower than slowdown threshold';
like $gcode, qr/F2500/, 'speed is not altered for travel moves';
@ -46,7 +49,7 @@ $config->set('disable_fan_first_layers', 0);
{
my $buffer = buffer($config);
$buffer->gcodegen->elapsed_time($buffer->config->fan_below_layer_time + 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->fan_below_layer_time + 1);
my $gcode = $buffer->append('G1 X100 E1 F3000', 0, 0, 0.4) . $buffer->flush;
unlike $gcode, qr/M106/, 'fan is not activated when elapsed time is greater than fan threshold';
}
@ -56,7 +59,7 @@ $config->set('disable_fan_first_layers', 0);
my $gcode = "";
for my $obj_id (0 .. 1) {
# use an elapsed time which is < the slowdown threshold but greater than it when summed twice
$buffer->gcodegen->elapsed_time($buffer->config->slowdown_below_layer_time - 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->slowdown_below_layer_time - 1);
$gcode .= $buffer->append("G1 X100 E1 F3000\n", $obj_id, 0, 0.4);
}
$gcode .= $buffer->flush;
@ -69,7 +72,7 @@ $config->set('disable_fan_first_layers', 0);
for my $layer_id (0 .. 1) {
for my $obj_id (0 .. 1) {
# use an elapsed time which is < the threshold but greater than it when summed twice
$buffer->gcodegen->elapsed_time($buffer->config->fan_below_layer_time - 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->fan_below_layer_time - 1);
$gcode .= $buffer->append("G1 X100 E1 F3000\n", $obj_id, $layer_id, 0.4 + 0.4*$layer_id + 0.1*$obj_id); # print same layer at distinct heights
}
}
@ -83,7 +86,7 @@ $config->set('disable_fan_first_layers', 0);
for my $layer_id (0 .. 1) {
for my $obj_id (0 .. 1) {
# use an elapsed time which is < the threshold even when summed twice
$buffer->gcodegen->elapsed_time($buffer->config->fan_below_layer_time/2 - 1);
$buffer->gcodegen->set_elapsed_time($buffer->config->fan_below_layer_time/2 - 1);
$gcode .= $buffer->append("G1 X100 E1 F3000\n", $obj_id, $layer_id, 0.4 + 0.4*$layer_id + 0.1*$obj_id); # print same layer at distinct heights
}
}

View File

@ -13,10 +13,8 @@ use Slic3r::Geometry qw(scale convex_hull);
use Slic3r::Test;
{
my $gcodegen = Slic3r::GCode->new(
layer_count => 1,
extruders => [],
);
my $gcodegen = Slic3r::GCode->new();
$gcodegen->set_layer_count(1);
$gcodegen->set_origin(Slic3r::Pointf->new(10, 10));
is_deeply $gcodegen->last_pos->arrayref, [scale -10, scale -10], 'last_pos is shifted correctly';
}

View File

@ -215,10 +215,12 @@ for my $class (qw(
Slic3r::ExtrusionPath
Slic3r::ExtrusionPath::Collection
Slic3r::Flow
Slic3r::GCode
Slic3r::GCode::AvoidCrossingPerimeters
Slic3r::GCode::OozePrevention
Slic3r::GCode::PlaceholderParser
Slic3r::GCode::Wipe
Slic3r::GCode::Writer
Slic3r::Geometry::BoundingBox
Slic3r::Geometry::BoundingBoxf
Slic3r::Geometry::BoundingBoxf3

View File

@ -97,4 +97,15 @@ Wipe::reset_path()
REGISTER_CLASS(Wipe, "GCode::Wipe");
#endif
GCode::GCode()
: enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0),
layer_index(-1), first_layer(false), elapsed_time(0), volumetric_speed(0),
last_pos_defined(false)
{
}
#ifdef SLIC3RXS
REGISTER_CLASS(GCode, "GCode");
#endif
}

View File

@ -3,7 +3,13 @@
#include <myinit.h>
#include "ExPolygon.hpp"
#include "GCodeWriter.hpp"
#include "Layer.hpp"
#include "MotionPlanner.hpp"
#include "Point.hpp"
#include "PlaceholderParser.hpp"
#include "Print.hpp"
#include "PrintConfig.hpp"
#include <string>
namespace Slic3r {
@ -54,6 +60,34 @@ class Wipe {
//std::string wipe(GCode &gcodegen, bool toolchange = false);
};
class GCode {
public:
/* Origin of print coordinates expressed in unscaled G-code coordinates.
This affects the input arguments supplied to the extrude*() and travel_to()
methods. */
Pointf origin;
FullPrintConfig config;
GCodeWriter writer;
PlaceholderParser* placeholder_parser;
OozePrevention ooze_prevention;
Wipe wipe;
AvoidCrossingPerimeters avoid_crossing_perimeters;
bool enable_loop_clipping;
bool enable_cooling_markers;
size_t layer_count;
int layer_index; // just a counter
Layer* layer;
std::map<PrintObject*,Point> _seam_position;
bool first_layer; // this flag triggers first layer speeds
unsigned int elapsed_time; // seconds
Point last_pos;
bool last_pos_defined;
double volumetric_speed;
GCode();
};
}
#endif

View File

@ -62,3 +62,89 @@
void set_path(Polyline* value)
%code{% THIS->path = *value; %};
};
%name{Slic3r::GCode} class GCode {
GCode();
~GCode();
Ref<Pointf> origin()
%code{% RETVAL = &(THIS->origin); %};
void _set_origin(Pointf* value)
%code{% THIS->origin = *value; %};
Ref<FullPrintConfig> config()
%code{% RETVAL = &(THIS->config); %};
Ref<GCodeWriter> writer()
%code{% RETVAL = &(THIS->writer); %};
Ref<PlaceholderParser> placeholder_parser()
%code{% RETVAL = THIS->placeholder_parser; %};
void set_placeholder_parser(PlaceholderParser* ptr)
%code{% THIS->placeholder_parser = ptr; %};
Ref<OozePrevention> ooze_prevention()
%code{% RETVAL = &(THIS->ooze_prevention); %};
Ref<Wipe> wipe()
%code{% RETVAL = &(THIS->wipe); %};
Ref<AvoidCrossingPerimeters> avoid_crossing_perimeters()
%code{% RETVAL = &(THIS->avoid_crossing_perimeters); %};
bool enable_loop_clipping()
%code{% RETVAL = THIS->enable_loop_clipping; %};
void set_enable_loop_clipping(bool value)
%code{% THIS->enable_loop_clipping = value; %};
bool enable_cooling_markers()
%code{% RETVAL = THIS->enable_cooling_markers; %};
void set_enable_cooling_markers(bool value)
%code{% THIS->enable_cooling_markers = value; %};
int layer_count()
%code{% RETVAL = THIS->layer_count; %};
void set_layer_count(int value)
%code{% THIS->layer_count = value; %};
int layer_index()
%code{% RETVAL = THIS->layer_index; %};
void set_layer_index(int value)
%code{% THIS->layer_index = value; %};
bool has_layer()
%code{% RETVAL = THIS->layer != NULL; %};
Ref<Layer> layer()
%code{% RETVAL = THIS->layer; %};
void set_layer(Layer* ptr)
%code{% THIS->layer = ptr; %};
bool _has_seam_position(PrintObject* ptr)
%code{% RETVAL = THIS->_seam_position.count(ptr) > 0; %};
Clone<Point> _seam_position(PrintObject* ptr)
%code{% RETVAL = THIS->_seam_position[ptr]; %};
void _set_seam_position(PrintObject* ptr, Point* pos)
%code{% THIS->_seam_position[ptr] = *pos; %};
bool first_layer()
%code{% RETVAL = THIS->first_layer; %};
void set_first_layer(bool value)
%code{% THIS->first_layer = value; %};
unsigned int elapsed_time()
%code{% RETVAL = THIS->elapsed_time; %};
void set_elapsed_time(unsigned int value)
%code{% THIS->elapsed_time = value; %};
bool last_pos_defined()
%code{% RETVAL = THIS->last_pos_defined; %};
Ref<Point> last_pos()
%code{% RETVAL = &(THIS->last_pos); %};
void set_last_pos(Point* value)
%code{% THIS->last_pos = *value; THIS->last_pos_defined = true; %};
double volumetric_speed()
%code{% RETVAL = THIS->volumetric_speed; %};
void set_volumetric_speed(double value)
%code{% THIS->volumetric_speed = value; %};
};

View File

@ -70,6 +70,9 @@
int ptr()
%code%{ RETVAL = (int)(intptr_t)THIS; %};
Ref<SupportLayer> as_support_layer()
%code%{ RETVAL = dynamic_cast<SupportLayer*>(THIS); %};
void make_slices();
void merge_slices();
bool any_internal_region_slice_contains_polyline(Polyline* polyline)
@ -81,6 +84,9 @@
%name{Slic3r::Layer::Support} class SupportLayer {
// owned by PrintObject, no constructor/destructor
Ref<Layer> as_layer()
%code%{ RETVAL = THIS; %};
Ref<ExPolygonCollection> support_islands()
%code%{ RETVAL = &THIS->support_islands; %};
Ref<ExtrusionEntityCollection> support_fills()

View File

@ -182,6 +182,10 @@ OozePrevention* O_OBJECT_SLIC3R
Ref<OozePrevention> O_OBJECT_SLIC3R_T
Clone<OozePrevention> O_OBJECT_SLIC3R_T
GCode* O_OBJECT_SLIC3R
Ref<GCode> O_OBJECT_SLIC3R_T
Clone<GCode> O_OBJECT_SLIC3R_T
MotionPlanner* O_OBJECT_SLIC3R
Ref<MotionPlanner> O_OBJECT_SLIC3R_T
Clone<MotionPlanner> O_OBJECT_SLIC3R_T

View File

@ -133,6 +133,14 @@
%typemap{Ref<Wipe>}{simple};
%typemap{Clone<Wipe>}{simple};
%typemap{OozePrevention*};
%typemap{Ref<OozePrevention>}{simple};
%typemap{Clone<OozePrevention>}{simple};
%typemap{GCode*};
%typemap{Ref<GCode>}{simple};
%typemap{Clone<GCode>}{simple};
%typemap{Points};
%typemap{Pointfs};