Browse Source

Ported more Slic3r::GCode methods to XS

Alessandro Ranellucci 9 years ago
parent
commit
b4019bb438

+ 1 - 140
lib/Slic3r/GCode.pm

@@ -8,13 +8,6 @@ use Slic3r::ExtrusionPath ':roles';
 use Slic3r::Geometry qw(epsilon scale unscale PI X Y B);
 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 {
     my ($self, $extruder_ids) = @_;
     
@@ -24,34 +17,6 @@ sub set_extruders {
     $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 {
     my ($self, $layer) = @_;
     
@@ -348,7 +313,7 @@ sub travel_to {
     if ($needs_retraction
         && $self->config->avoid_crossing_perimeters
         && !$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
         $needs_retraction = $self->needs_retraction($travel, $role);
@@ -404,51 +369,6 @@ sub needs_retraction {
     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 {
     my ($self, $extruder_id) = @_;
     
@@ -535,63 +455,4 @@ sub post_toolchange {
     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;

+ 2 - 2
t/shells.t

@@ -192,7 +192,7 @@ use Slic3r::Test;
                 push @z_steps, $info->{dist_Z}
                     if $started_extruding && $info->{dist_Z} > 0;
                 $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') {
                 $first_layer_temperature_set = 1 if $args->{S} == 205;
                 $temperature_set = 1 if $args->{S} == 200;
@@ -271,7 +271,7 @@ use Slic3r::Test;
                 foreach my $segment (@this_layer) {
                     # check that segment's dist_Z is proportioned to its dist_XY
                     $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 = ();

+ 1 - 0
xs/MANIFEST

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

+ 161 - 6
xs/src/libslic3r/GCode.cpp

@@ -36,16 +36,15 @@ AvoidCrossingPerimeters::init_layer_mp(const ExPolygons &islands)
 }
 
 Polyline
-AvoidCrossingPerimeters::travel_to(Point point, const Pointf &gcodegen_origin,
-    const Point &gcodegen_last_pos)
+AvoidCrossingPerimeters::travel_to(GCode &gcodegen, Point point)
 {
     if (this->use_external_mp || this->use_external_mp_once) {
         // get current origin set in gcodegen
         // (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
-        Point last_pos = gcodegen_last_pos;
+        Point last_pos = gcodegen.last_pos();
         last_pos.translate(scaled_origin);
         
         // 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());
         return travel;
     } 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();
 }
 
+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
 REGISTER_CLASS(Wipe, "GCode::Wipe");
 #endif
@@ -100,8 +155,108 @@ REGISTER_CLASS(Wipe, "GCode::Wipe");
 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)
+        _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

+ 16 - 8
xs/src/libslic3r/GCode.hpp

@@ -14,7 +14,7 @@
 
 namespace Slic3r {
 
-// draft for a binary representation of a G-code line
+class GCode;
 
 class AvoidCrossingPerimeters {
     public:
@@ -31,10 +31,7 @@ class AvoidCrossingPerimeters {
     ~AvoidCrossingPerimeters();
     void init_external_mp(const ExPolygons &islands);
     void init_layer_mp(const ExPolygons &islands);
-    
-    //Polyline travel_to(GCode &gcodegen, const Point &point);
-    Polyline travel_to(Point point, const Pointf &gcodegen_origin,
-        const Point &gcodegen_last_pos);
+    Polyline travel_to(GCode &gcodegen, Point point);
     
     private:
     MotionPlanner* _external_mp;
@@ -57,7 +54,7 @@ class Wipe {
     Wipe();
     bool has_path();
     void reset_path();
-    //std::string wipe(GCode &gcodegen, bool toolchange = false);
+    std::string wipe(GCode &gcodegen, bool toolchange = false);
 };
 
 class GCode {
@@ -81,11 +78,22 @@ class GCode {
     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();
+    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;
 };
 
 }

+ 18 - 0
xs/src/libslic3r/MultiPoint.cpp

@@ -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
 MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
 {

+ 3 - 0
xs/src/libslic3r/MultiPoint.hpp

@@ -33,6 +33,9 @@ class MultiPoint
     bool has_boundary_point(const Point &point) const;
     BoundingBox bounding_box() const;
     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);
     

+ 17 - 0
xs/t/21_gcode.t

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

+ 18 - 9
xs/xsp/GCode.xsp

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