diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index b2ba77e28..57aabe31b 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -194,6 +194,7 @@ sub thread_cleanup { *Slic3r::ExtrusionPath::DESTROY = sub {}; *Slic3r::ExtrusionPath::Collection::DESTROY = sub {}; *Slic3r::Flow::DESTROY = sub {}; + *Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {}; *Slic3r::GCode::PlaceholderParser::DESTROY = sub {}; *Slic3r::GCode::Writer::DESTROY = sub {}; *Slic3r::Geometry::BoundingBox::DESTROY = sub {}; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index b486ba0b0..f8388568b 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -365,15 +365,15 @@ sub travel_to { if ($needs_retraction && $self->config->avoid_crossing_perimeters && !$self->avoid_crossing_perimeters->disable_once) { - $travel = $self->avoid_crossing_perimeters->travel_to($self, $point); + $travel = $self->avoid_crossing_perimeters->travel_to($point, $self->origin, $self->last_pos); # check again whether the new travel path still needs a retraction $needs_retraction = $self->needs_retraction($travel, $role); } # Re-allow avoid_crossing_perimeters for the next travel moves - $self->avoid_crossing_perimeters->disable_once(0); - $self->avoid_crossing_perimeters->use_external_mp_once(0); + $self->avoid_crossing_perimeters->set_disable_once(0); + $self->avoid_crossing_perimeters->set_use_external_mp_once(0); # generate G-code for the travel move my $gcode = ""; @@ -615,53 +615,4 @@ sub wipe { return $gcode; } -package Slic3r::GCode::AvoidCrossingPerimeters; -use Moo; - -has '_external_mp' => (is => 'rw'); -has '_layer_mp' => (is => 'rw'); -has 'use_external_mp' => (is => 'rw', default => sub {0}); -has 'use_external_mp_once' => (is => 'rw', default => sub {0}); # this flag triggers the use of the external configuration space for avoid_crossing_perimeters for the next travel move - -# this flag disables avoid_crossing_perimeters just for the next travel move -# we enable it by default for the first travel move in print -has 'disable_once' => (is => 'rw', default => sub {1}); - -sub init_external_mp { - my ($self, $islands) = @_; - $self->_external_mp(Slic3r::MotionPlanner->new($islands)); -} - -sub init_layer_mp { - my ($self, $islands) = @_; - $self->_layer_mp(Slic3r::MotionPlanner->new($islands)); -} - -sub travel_to { - my ($self, $gcodegen, $point) = @_; - - if ($self->use_external_mp || $self->use_external_mp_once) { - # get current origin set in $gcodegen - # (the one that will be used to translate the G-code coordinates by) - my $scaled_origin = Slic3r::Point->new_scale(@{$gcodegen->origin}); - - # represent last_pos in absolute G-code coordinates - my $last_pos = $gcodegen->last_pos->clone; - $last_pos->translate(@$scaled_origin); - - # represent $point in absolute G-code coordinates - $point = $point->clone; - $point->translate(@$scaled_origin); - # calculate path - my $travel = $self->_external_mp->shortest_path($last_pos, $point); - - # translate the path back into the shifted coordinate system that $gcodegen - # is currently using for writing coordinates - $travel->translate(@{$scaled_origin->negative}); - return $travel; - } else { - return $self->_layer_mp->shortest_path($gcodegen->last_pos, $point); - } -} - 1; diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index 1b7cfbc4b..b71deaf60 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -248,7 +248,7 @@ sub export { 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->avoid_crossing_perimeters->use_external_mp_once(1); + $gcodegen->avoid_crossing_perimeters->set_use_external_mp_once(1); print $fh $gcodegen->retract; print $fh $gcodegen->travel_to( Slic3r::Point->new(0,0), @@ -258,7 +258,7 @@ sub export { $gcodegen->enable_cooling_markers(1); # disable motion planner when traveling to first object point - $gcodegen->avoid_crossing_perimeters->disable_once(1); + $gcodegen->avoid_crossing_perimeters->set_disable_once(1); } my @layers = sort { $a->print_z <=> $b->print_z } @{$object->layers}, @{$object->support_layers}; @@ -398,7 +398,7 @@ sub process_layer { && !$self->_skirt_done->{$layer->print_z} && (!$layer->isa('Slic3r::Layer::Support') || $layer->id < $object->config->raft_layers)) { $self->_gcodegen->set_origin(Slic3r::Pointf->new(0,0)); - $self->_gcodegen->avoid_crossing_perimeters->use_external_mp(1); + $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(1); my @extruder_ids = map { $_->id } @{$self->_gcodegen->writer->extruders}; $gcode .= $self->_gcodegen->set_extruder($extruder_ids[0]); # skip skirt if we have a large brim @@ -431,12 +431,12 @@ sub process_layer { } } $self->_skirt_done->{$layer->print_z} = 1; - $self->_gcodegen->avoid_crossing_perimeters->use_external_mp(0); + $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(0); # allow a straight travel move to the first object point if this is the first layer # (but don't in next layers) if ($layer->id == 0) { - $self->_gcodegen->avoid_crossing_perimeters->disable_once(1); + $self->_gcodegen->avoid_crossing_perimeters->set_disable_once(1); } } @@ -444,19 +444,19 @@ sub process_layer { if (!$self->_brim_done) { $gcode .= $self->_gcodegen->set_extruder($self->print->regions->[0]->config->perimeter_extruder-1); $self->_gcodegen->set_origin(Slic3r::Pointf->new(0,0)); - $self->_gcodegen->avoid_crossing_perimeters->use_external_mp(1); + $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(1); $gcode .= $self->_gcodegen->extrude_loop($_, 'brim', $object->config->support_material_speed) for @{$self->print->brim}; $self->_brim_done(1); - $self->_gcodegen->avoid_crossing_perimeters->use_external_mp(0); + $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(0); # allow a straight travel move to the first object point - $self->_gcodegen->avoid_crossing_perimeters->disable_once(1); + $self->_gcodegen->avoid_crossing_perimeters->set_disable_once(1); } for my $copy (@$object_copies) { # when starting a new object, use the external motion planner for the first travel move - $self->_gcodegen->avoid_crossing_perimeters->use_external_mp_once(1) if ($self->_last_obj_copy // '') ne "$copy"; + $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp_once(1) if ($self->_last_obj_copy // '') ne "$copy"; $self->_last_obj_copy("$copy"); $self->_gcodegen->set_origin(Slic3r::Pointf->new(map unscale $copy->[$_], X,Y)); diff --git a/xs/MANIFEST b/xs/MANIFEST index 63e454f72..7d7923d26 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -1670,6 +1670,7 @@ src/libslic3r/ExtrusionEntityCollection.cpp src/libslic3r/ExtrusionEntityCollection.hpp src/libslic3r/Flow.cpp src/libslic3r/Flow.hpp +src/libslic3r/GCode.cpp src/libslic3r/GCode.hpp src/libslic3r/GCodeWriter.cpp src/libslic3r/GCodeWriter.hpp @@ -1762,6 +1763,7 @@ xsp/ExtrusionEntityCollection.xsp xsp/ExtrusionLoop.xsp xsp/ExtrusionPath.xsp xsp/Flow.xsp +xsp/GCode.xsp xsp/GCodeWriter.xsp xsp/Geometry.xsp xsp/GUI_3DScene.xsp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 842f4526f..3196eb320 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -215,6 +215,7 @@ for my $class (qw( Slic3r::ExtrusionPath Slic3r::ExtrusionPath::Collection Slic3r::Flow + Slic3r::GCode::AvoidCrossingPerimeters Slic3r::GCode::PlaceholderParser Slic3r::Geometry::BoundingBox Slic3r::Geometry::BoundingBoxf diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp new file mode 100644 index 000000000..b21a9eca7 --- /dev/null +++ b/xs/src/libslic3r/GCode.cpp @@ -0,0 +1,70 @@ +#include "GCode.hpp" + +namespace Slic3r { + +AvoidCrossingPerimeters::AvoidCrossingPerimeters() + : use_external_mp(false), use_external_mp_once(false), disable_once(true), + _external_mp(NULL), _layer_mp(NULL) +{ +} + +AvoidCrossingPerimeters::~AvoidCrossingPerimeters() +{ + if (this->_external_mp != NULL) + delete this->_external_mp; + + if (this->_layer_mp != NULL) + delete this->_layer_mp; +} + +void +AvoidCrossingPerimeters::init_external_mp(const ExPolygons &islands) +{ + if (this->_external_mp != NULL) + delete this->_external_mp; + + this->_external_mp = new MotionPlanner(islands); +} + +void +AvoidCrossingPerimeters::init_layer_mp(const ExPolygons &islands) +{ + if (this->_layer_mp != NULL) + delete this->_layer_mp; + + this->_layer_mp = new MotionPlanner(islands); +} + +Polyline +AvoidCrossingPerimeters::travel_to(Point point, const Pointf &gcodegen_origin, + const Point &gcodegen_last_pos) +{ + 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); + + // represent last_pos in absolute G-code coordinates + Point last_pos = gcodegen_last_pos; + last_pos.translate(scaled_origin); + + // represent point in absolute G-code coordinates + point.translate(scaled_origin); + + // calculate path + Polyline travel = this->_external_mp->shortest_path(last_pos, point); + + // translate the path back into the shifted coordinate system that gcodegen + // is currently using for writing coordinates + travel.translate(scaled_origin.negative()); + return travel; + } else { + return this->_layer_mp->shortest_path(gcodegen_last_pos, point); + } +} + +#ifdef SLIC3RXS +REGISTER_CLASS(AvoidCrossingPerimeters, "GCode::AvoidCrossingPerimeters"); +#endif + +} diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index a889532ea..a9af44781 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -2,32 +2,37 @@ #define slic3r_GCode_hpp_ #include +#include "ExPolygon.hpp" +#include "MotionPlanner.hpp" #include namespace Slic3r { // draft for a binary representation of a G-code line -enum GCodeCmdType { - gcctSyncMotion, - gcctExtrude, - gcctResetE, - gcctSetTemp, - gcctSetTempWait, - gcctToolchange, - gcctCustom -}; - -class GCodeCmd { +class AvoidCrossingPerimeters { public: - GCodeCmdType type; - float X, Y, Z, E, F; - unsigned short T, S; - std::string custom, comment; - float xy_dist; // cache - GCodeCmd(GCodeCmdType type) - : type(type), X(0), Y(0), Z(0), E(0), F(0), T(-1), S(0), xy_dist(-1) {}; + // this flag triggers the use of the external configuration space + bool use_external_mp; + bool use_external_mp_once; // just for the next travel move + + // this flag disables avoid_crossing_perimeters just for the next travel move + // we enable it by default for the first travel move in print + bool disable_once; + + 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); + + private: + MotionPlanner* _external_mp; + MotionPlanner* _layer_mp; }; } diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp new file mode 100644 index 000000000..007b2b164 --- /dev/null +++ b/xs/xsp/GCode.xsp @@ -0,0 +1,31 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "libslic3r/GCode.hpp" +%} + +%name{Slic3r::GCode::AvoidCrossingPerimeters} class AvoidCrossingPerimeters { + AvoidCrossingPerimeters(); + ~AvoidCrossingPerimeters(); + + void init_external_mp(ExPolygons islands); + void init_layer_mp(ExPolygons islands); + Clone travel_to(Point* point, Pointf* gcodegen_origin, Point* gcodegen_last_pos) + %code{% RETVAL = THIS->travel_to(*point, *gcodegen_origin, *gcodegen_last_pos); %}; + + bool use_external_mp() + %code{% RETVAL = THIS->use_external_mp; %}; + void set_use_external_mp(bool value) + %code{% THIS->use_external_mp = value; %}; + + bool use_external_mp_once() + %code{% RETVAL = THIS->use_external_mp_once; %}; + void set_use_external_mp_once(bool value) + %code{% THIS->use_external_mp_once = value; %}; + + bool disable_once() + %code{% RETVAL = THIS->disable_once; %}; + void set_disable_once(bool value) + %code{% THIS->disable_once = value; %}; +}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index da9d3adc7..fb1288990 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -170,6 +170,10 @@ PlaceholderParser* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T +AvoidCrossingPerimeters* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + MotionPlanner* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index afc256d13..53e021337 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -125,6 +125,10 @@ %typemap{Ref}{simple}; %typemap{Clone}{simple}; +%typemap{AvoidCrossingPerimeters*}; +%typemap{Ref}{simple}; +%typemap{Clone}{simple}; + %typemap{Points}; %typemap{Pointfs};