Finished porting Slic3r::GCode to XS (speed boost!)
This commit is contained in:
parent
0ad4296aaf
commit
3e739b87da
@ -44,7 +44,6 @@ use Slic3r::Flow;
|
||||
use Slic3r::Format::AMF;
|
||||
use Slic3r::Format::OBJ;
|
||||
use Slic3r::Format::STL;
|
||||
use Slic3r::GCode;
|
||||
use Slic3r::GCode::ArcFitting;
|
||||
use Slic3r::GCode::CoolingBuffer;
|
||||
use Slic3r::GCode::MotionPlanner;
|
||||
@ -77,7 +76,6 @@ use Unicode::Normalize;
|
||||
use constant SCALING_FACTOR => 0.000001;
|
||||
use constant RESOLUTION => 0.0125;
|
||||
use constant SCALED_RESOLUTION => RESOLUTION / SCALING_FACTOR;
|
||||
use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI;
|
||||
use constant LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER => 0.15;
|
||||
use constant INFILL_OVERLAP_OVER_SPACING => 0.3;
|
||||
use constant EXTERNAL_INFILL_MARGIN => 3;
|
||||
|
@ -1,143 +0,0 @@
|
||||
package Slic3r::GCode;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use List::Util qw(min max first);
|
||||
use Slic3r::ExtrusionLoop ':roles';
|
||||
use Slic3r::ExtrusionPath ':roles';
|
||||
use Slic3r::Geometry qw(epsilon scale unscale PI X Y B);
|
||||
use Slic3r::Geometry::Clipper qw(union_ex);
|
||||
|
||||
sub extrude {
|
||||
my $self = shift;
|
||||
|
||||
$_[0]->isa('Slic3r::ExtrusionLoop')
|
||||
? $self->extrude_loop(@_)
|
||||
: $self->extrude_path(@_);
|
||||
}
|
||||
|
||||
sub extrude_loop {
|
||||
my ($self, $loop, $description, $speed) = @_;
|
||||
|
||||
# make a copy; don't modify the orientation of the original loop object otherwise
|
||||
# next copies (if any) would not detect the correct orientation
|
||||
$loop = $loop->clone;
|
||||
|
||||
# extrude all loops ccw
|
||||
my $was_clockwise = $loop->make_counter_clockwise;
|
||||
|
||||
# find the point of the loop that is closest to the current extruder position
|
||||
# or randomize if requested
|
||||
my $last_pos = $self->last_pos;
|
||||
if ($self->config->spiral_vase) {
|
||||
$loop->split_at($last_pos);
|
||||
} elsif ($self->config->seam_position eq 'nearest' || $self->config->seam_position eq 'aligned') {
|
||||
# simplify polygon in order to skip false positives in concave/convex detection
|
||||
# ($loop is always ccw as $polygon->simplify only works on ccw polygons)
|
||||
my $polygon = $loop->polygon;
|
||||
my @simplified = @{$polygon->simplify(scale $self->config->get_at('nozzle_diameter', $self->writer->extruder->id)/2)};
|
||||
|
||||
# restore original winding order so that concave and convex detection always happens
|
||||
# on the right/outer side of the polygon
|
||||
if ($was_clockwise) {
|
||||
$_->reverse for @simplified;
|
||||
}
|
||||
|
||||
# concave vertices have priority
|
||||
my @candidates = map @{$_->concave_points(PI*4/3)}, @simplified;
|
||||
|
||||
# if no concave points were found, look for convex vertices
|
||||
@candidates = map @{$_->convex_points(PI*2/3)}, @simplified if !@candidates;
|
||||
|
||||
# retrieve the last start position for this object
|
||||
if ($self->has_layer) {
|
||||
if ($self->_has_seam_position($self->layer->object)) {
|
||||
$last_pos = $self->_seam_position($self->layer->object);
|
||||
}
|
||||
}
|
||||
|
||||
my $point;
|
||||
if ($self->config->seam_position eq 'nearest') {
|
||||
@candidates = @$polygon if !@candidates;
|
||||
$point = $last_pos->nearest_point(\@candidates);
|
||||
if (!$loop->split_at_vertex($point)) {
|
||||
# On 32-bit Linux, Clipper will change some point coordinates by 1 unit
|
||||
# while performing simplify_polygons(), thus split_at_vertex() won't
|
||||
# find them anymore.
|
||||
$loop->split_at($point);
|
||||
}
|
||||
} elsif (@candidates) {
|
||||
my @non_overhang = grep !$loop->has_overhang_point($_), @candidates;
|
||||
@candidates = @non_overhang if @non_overhang;
|
||||
$point = $last_pos->nearest_point(\@candidates);
|
||||
if (!$loop->split_at_vertex($point)) {
|
||||
$loop->split_at($point);
|
||||
}
|
||||
} else {
|
||||
$point = $last_pos->projection_onto_polygon($polygon);
|
||||
$loop->split_at($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;
|
||||
my $centroid = $polygon->centroid;
|
||||
$last_pos = Slic3r::Point->new($polygon->bounding_box->x_max, $centroid->y); #))
|
||||
$last_pos->rotate(rand(2*PI), $centroid);
|
||||
}
|
||||
$loop->split_at($last_pos);
|
||||
}
|
||||
|
||||
# clip the path to avoid the extruder to get exactly on the first point of the loop;
|
||||
# if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
# we discard it in that case
|
||||
my $clip_length = $self->enable_loop_clipping
|
||||
? scale($self->config->get_at('nozzle_diameter', $self->writer->extruder->id)) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER
|
||||
: 0;
|
||||
|
||||
# get paths
|
||||
my @paths = @{$loop->clip_end($clip_length)};
|
||||
return '' if !@paths;
|
||||
|
||||
# apply the small perimeter speed
|
||||
if ($paths[0]->is_perimeter && $loop->length <= &Slic3r::SMALL_PERIMETER_LENGTH) {
|
||||
$speed //= $self->config->get_abs_value('small_perimeter_speed');
|
||||
}
|
||||
|
||||
# extrude along the path
|
||||
my $gcode = join '', map $self->_extrude_path($_, $description // "", $speed // -1), @paths;
|
||||
|
||||
# reset acceleration
|
||||
$gcode .= $self->writer->set_acceleration($self->config->default_acceleration);
|
||||
|
||||
$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 && $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)
|
||||
my @points = ($paths[0][1], $paths[-1][-2]);
|
||||
@points = reverse @points if $was_clockwise;
|
||||
my $angle = $paths[0]->first_point->ccw_angle(@points) / 3;
|
||||
|
||||
# turn left if contour, turn right if hole
|
||||
$angle *= -1 if $was_clockwise;
|
||||
|
||||
# create the destination point along the first segment and rotate it
|
||||
# we make sure we don't exceed the segment length because we don't know
|
||||
# the rotation of the second segment so we might cross the object boundary
|
||||
my $first_segment = Slic3r::Line->new(@{$paths[0]->polyline}[0,1]);
|
||||
my $distance = min(scale($self->config->get_at('nozzle_diameter', $self->writer->extruder->id)), $first_segment->length);
|
||||
my $point = $first_segment->point_at($distance);
|
||||
$point->rotate($angle, $first_segment->a);
|
||||
|
||||
# generate the travel move
|
||||
$gcode .= $self->writer->travel_to_xy($self->point_to_gcode($point), "move inwards before travel");
|
||||
}
|
||||
|
||||
return $gcode;
|
||||
}
|
||||
|
||||
1;
|
@ -43,7 +43,7 @@ sub process {
|
||||
my $rel_flow_rate = $info->{dist_E} / $info->{dist_XY};
|
||||
|
||||
# Then calculate absolute flow rate (mm/sec of feedstock)
|
||||
my $flow_rate = $rel_flow_rate * $args->{F} / 60;
|
||||
my $flow_rate = $rel_flow_rate * $F / 60;
|
||||
|
||||
# And finally calculate advance by using the user-configured K factor.
|
||||
my $new_advance = $self->config->pressure_advance * ($flow_rate**2);
|
||||
|
@ -384,7 +384,7 @@ sub process_layer {
|
||||
$pp->set('layer_z' => $layer->print_z);
|
||||
$gcode .= $pp->process($self->print->config->before_layer_gcode) . "\n";
|
||||
}
|
||||
$gcode .= $self->_gcodegen->change_layer($layer); # this will increase $self->_gcodegen->layer_index
|
||||
$gcode .= $self->_gcodegen->change_layer($layer->as_layer); # this will increase $self->_gcodegen->layer_index
|
||||
if ($self->print->config->layer_gcode) {
|
||||
my $pp = $self->_gcodegen->placeholder_parser->clone;
|
||||
$pp->set('layer_num' => $self->_gcodegen->layer_index);
|
||||
@ -592,7 +592,7 @@ sub _extrude_perimeters {
|
||||
my $gcode = "";
|
||||
foreach my $region_id (sort keys %$entities_by_region) {
|
||||
$self->_gcodegen->config->apply_region_config($self->print->get_region($region_id)->config);
|
||||
$gcode .= $self->_gcodegen->extrude($_, 'perimeter')
|
||||
$gcode .= $self->_gcodegen->extrude($_, 'perimeter', -1)
|
||||
for @{ $entities_by_region->{$region_id} };
|
||||
}
|
||||
return $gcode;
|
||||
@ -608,10 +608,10 @@ sub _extrude_infill {
|
||||
my $collection = Slic3r::ExtrusionPath::Collection->new(@{ $entities_by_region->{$region_id} });
|
||||
for my $fill (@{$collection->chained_path_from($self->_gcodegen->last_pos, 0)}) {
|
||||
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
|
||||
$gcode .= $self->_gcodegen->extrude($_, 'infill')
|
||||
$gcode .= $self->_gcodegen->extrude($_, 'infill', -1)
|
||||
for @{$fill->chained_path_from($self->_gcodegen->last_pos, 0)};
|
||||
} else {
|
||||
$gcode .= $self->_gcodegen->extrude($fill, 'infill') ;
|
||||
$gcode .= $self->_gcodegen->extrude($fill, 'infill', -1) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "GCode.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -320,9 +321,173 @@ GCode::change_layer(const Layer &layer)
|
||||
}
|
||||
|
||||
std::string
|
||||
GCode::extrude_path(const ExtrusionPath &path, std::string description, double speed)
|
||||
GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
|
||||
{
|
||||
std::string gcode = this->_extrude_path(path, description, speed);
|
||||
// get a copy; don't modify the orientation of the original loop object otherwise
|
||||
// next copies (if any) would not detect the correct orientation
|
||||
|
||||
// extrude all loops ccw
|
||||
bool was_clockwise = loop.make_counter_clockwise();
|
||||
|
||||
// find the point of the loop that is closest to the current extruder position
|
||||
// or randomize if requested
|
||||
Point last_pos = this->last_pos();
|
||||
if (this->config.spiral_vase) {
|
||||
loop.split_at(last_pos);
|
||||
} else if (this->config.seam_position == spNearest || this->config.seam_position == spAligned) {
|
||||
Polygon polygon = loop.polygon();
|
||||
|
||||
// simplify polygon in order to skip false positives in concave/convex detection
|
||||
// (loop is always ccw as polygon.simplify() only works on ccw polygons)
|
||||
Polygons simplified = polygon.simplify(scale_(EXTRUDER_CONFIG(nozzle_diameter))/2);
|
||||
|
||||
// restore original winding order so that concave and convex detection always happens
|
||||
// on the right/outer side of the polygon
|
||||
if (was_clockwise) {
|
||||
for (Polygons::iterator p = simplified.begin(); p != simplified.end(); ++p)
|
||||
p->reverse();
|
||||
}
|
||||
|
||||
// concave vertices have priority
|
||||
Points candidates;
|
||||
for (Polygons::const_iterator p = simplified.begin(); p != simplified.end(); ++p) {
|
||||
Points concave = p->concave_points(PI*4/3);
|
||||
candidates.insert(candidates.end(), concave.begin(), concave.end());
|
||||
}
|
||||
|
||||
// if no concave points were found, look for convex vertices
|
||||
if (candidates.empty()) {
|
||||
for (Polygons::const_iterator p = simplified.begin(); p != simplified.end(); ++p) {
|
||||
Points convex = p->convex_points(PI*2/3);
|
||||
candidates.insert(candidates.end(), convex.begin(), convex.end());
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve the last start position for this object
|
||||
if (this->layer != NULL && this->_seam_position.count(this->layer->object()) > 0) {
|
||||
last_pos = this->_seam_position[this->layer->object()];
|
||||
}
|
||||
|
||||
Point point;
|
||||
if (this->config.seam_position == spNearest) {
|
||||
if (candidates.empty()) candidates = polygon.points;
|
||||
last_pos.nearest_point(candidates, &point);
|
||||
|
||||
// On 32-bit Linux, Clipper will change some point coordinates by 1 unit
|
||||
// while performing simplify_polygons(), thus split_at_vertex() won't
|
||||
// find them anymore.
|
||||
if (!loop.split_at_vertex(point)) loop.split_at(point);
|
||||
} else if (!candidates.empty()) {
|
||||
Points non_overhang;
|
||||
for (Points::const_iterator p = candidates.begin(); p != candidates.end(); ++p) {
|
||||
if (!loop.has_overhang_point(*p))
|
||||
non_overhang.push_back(*p);
|
||||
}
|
||||
|
||||
if (!non_overhang.empty())
|
||||
candidates = non_overhang;
|
||||
|
||||
last_pos.nearest_point(candidates, &point);
|
||||
if (!loop.split_at_vertex(point)) loop.split_at(point); // see note above
|
||||
} else {
|
||||
point = last_pos.projection_onto(polygon);
|
||||
loop.split_at(point);
|
||||
}
|
||||
if (this->layer != NULL)
|
||||
this->_seam_position[this->layer->object()] = point;
|
||||
} else if (this->config.seam_position == spRandom) {
|
||||
if (loop.role == elrContourInternalPerimeter) {
|
||||
Polygon polygon = loop.polygon();
|
||||
Point centroid = polygon.centroid();
|
||||
last_pos = Point(polygon.bounding_box().max.x, centroid.y);
|
||||
last_pos.rotate(rand() % 2*PI, centroid);
|
||||
}
|
||||
loop.split_at(last_pos);
|
||||
}
|
||||
|
||||
// clip the path to avoid the extruder to get exactly on the first point of the loop;
|
||||
// if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
// we discard it in that case
|
||||
double clip_length = this->enable_loop_clipping
|
||||
? scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER
|
||||
: 0;
|
||||
|
||||
// get paths
|
||||
ExtrusionPaths paths;
|
||||
loop.clip_end(clip_length, &paths);
|
||||
if (paths.empty()) return "";
|
||||
|
||||
// apply the small perimeter speed
|
||||
if (paths.front().is_perimeter() && loop.length() <= SMALL_PERIMETER_LENGTH) {
|
||||
if (speed == -1) speed = this->config.get_abs_value("small_perimeter_speed");
|
||||
}
|
||||
|
||||
// extrude along the path
|
||||
std::string gcode;
|
||||
for (ExtrusionPaths::const_iterator path = paths.begin(); path != paths.end(); ++path)
|
||||
gcode += this->_extrude(*path, description, speed);
|
||||
|
||||
// reset acceleration
|
||||
gcode += this->writer.set_acceleration(this->config.default_acceleration.value);
|
||||
|
||||
if (this->wipe.enable)
|
||||
this->wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path
|
||||
|
||||
// make a little move inwards before leaving loop
|
||||
if (paths.back().role == erExternalPerimeter && this->layer != NULL && this->config.perimeters > 1) {
|
||||
Polyline &last_path_polyline = paths.back().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)
|
||||
Point a = paths.front().polyline.points[1]; // second point
|
||||
Point b = *(paths.back().polyline.points.end()-3); // second to last point
|
||||
if (was_clockwise) {
|
||||
// swap points
|
||||
Point c = a; a = b; b = c;
|
||||
}
|
||||
|
||||
double angle = paths.front().first_point().ccw_angle(a, b) / 3;
|
||||
|
||||
// turn left if contour, turn right if hole
|
||||
if (was_clockwise) angle *= -1;
|
||||
|
||||
// create the destination point along the first segment and rotate it
|
||||
// we make sure we don't exceed the segment length because we don't know
|
||||
// the rotation of the second segment so we might cross the object boundary
|
||||
Line first_segment(
|
||||
paths.front().polyline.points[0],
|
||||
paths.front().polyline.points[1]
|
||||
);
|
||||
double distance = std::min(
|
||||
scale_(EXTRUDER_CONFIG(nozzle_diameter)),
|
||||
first_segment.length()
|
||||
);
|
||||
Point point = first_segment.point_at(distance);
|
||||
point.rotate(angle, first_segment.a);
|
||||
|
||||
// generate the travel move
|
||||
gcode += this->writer.travel_to_xy(this->point_to_gcode(point), "move inwards before travel");
|
||||
}
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string
|
||||
GCode::extrude(const ExtrusionEntity &entity, std::string description, double speed)
|
||||
{
|
||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity)) {
|
||||
return this->extrude(*path, description, speed);
|
||||
} else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity)) {
|
||||
return this->extrude(*loop, description, speed);
|
||||
} else {
|
||||
CONFESS("Invalid argument supplied to extrude()");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
GCode::extrude(const ExtrusionPath &path, std::string description, double speed)
|
||||
{
|
||||
std::string gcode = this->_extrude(path, description, speed);
|
||||
|
||||
// reset acceleration
|
||||
gcode += this->writer.set_acceleration(this->config.default_acceleration.value);
|
||||
@ -331,7 +496,7 @@ GCode::extrude_path(const ExtrusionPath &path, std::string description, double s
|
||||
}
|
||||
|
||||
std::string
|
||||
GCode::_extrude_path(ExtrusionPath path, std::string description, double speed)
|
||||
GCode::_extrude(ExtrusionPath path, std::string description, double speed)
|
||||
{
|
||||
path.simplify(SCALED_RESOLUTION);
|
||||
|
||||
|
@ -80,7 +80,7 @@ class GCode {
|
||||
size_t layer_count;
|
||||
int layer_index; // just a counter
|
||||
const Layer* layer;
|
||||
std::map<PrintObject*,Point> _seam_position;
|
||||
std::map<const PrintObject*,Point> _seam_position;
|
||||
bool first_layer; // this flag triggers first layer speeds
|
||||
unsigned int elapsed_time; // seconds
|
||||
double volumetric_speed;
|
||||
@ -94,8 +94,9 @@ class GCode {
|
||||
void set_origin(const Pointf &pointf);
|
||||
std::string preamble();
|
||||
std::string change_layer(const Layer &layer);
|
||||
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 extrude(const ExtrusionEntity &entity, std::string description = "", double speed = -1);
|
||||
std::string extrude(ExtrusionLoop loop, std::string description = "", double speed = -1);
|
||||
std::string extrude(const 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);
|
||||
@ -106,6 +107,7 @@ class GCode {
|
||||
private:
|
||||
Point _last_pos;
|
||||
bool _last_pos_defined;
|
||||
std::string _extrude(ExtrusionPath path, std::string description = "", double speed = -1);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,12 @@ Layer::object()
|
||||
return this->_object;
|
||||
}
|
||||
|
||||
const PrintObject*
|
||||
Layer::object() const
|
||||
{
|
||||
return this->_object;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
Layer::region_count()
|
||||
|
@ -76,6 +76,7 @@ class Layer {
|
||||
size_t id() const;
|
||||
void set_id(size_t id);
|
||||
PrintObject* object();
|
||||
const PrintObject* object() const;
|
||||
|
||||
Layer *upper_layer;
|
||||
Layer *lower_layer;
|
||||
|
@ -13,6 +13,8 @@
|
||||
#define RESOLUTION 0.0125
|
||||
#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
|
||||
#define PI 3.141592653589793238
|
||||
#define LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER 0.15
|
||||
#define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI
|
||||
#define scale_(val) (val / SCALING_FACTOR)
|
||||
#define unscale(val) (val * SCALING_FACTOR)
|
||||
#define SCALED_EPSILON scale_(EPSILON)
|
||||
|
@ -124,13 +124,6 @@
|
||||
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)
|
||||
@ -160,10 +153,10 @@
|
||||
std::string preamble();
|
||||
std::string change_layer(Layer* layer)
|
||||
%code{% RETVAL = THIS->change_layer(*layer); %};
|
||||
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); %};
|
||||
%name{extrude_loop} std::string extrude(ExtrusionLoop* loop, std::string description = "", double speed = -1)
|
||||
%code{% RETVAL = THIS->extrude(*loop, description, speed); %};
|
||||
%name{extrude_path} std::string extrude(ExtrusionPath* path, std::string description = "", double speed = -1)
|
||||
%code{% RETVAL = THIS->extrude(*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)
|
||||
@ -173,4 +166,18 @@
|
||||
std::string set_extruder(unsigned int extruder_id);
|
||||
Clone<Pointf> point_to_gcode(Point* point)
|
||||
%code{% RETVAL = THIS->point_to_gcode(*point); %};
|
||||
|
||||
%{
|
||||
std::string
|
||||
GCode::extrude(entity, description, speed)
|
||||
SV* entity
|
||||
std::string description;
|
||||
double speed;
|
||||
CODE:
|
||||
ExtrusionEntity* e = (ExtrusionEntity *)SvIV((SV*)SvRV( entity ));
|
||||
RETVAL = THIS->extrude(*e, description, speed);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
%}
|
||||
|
||||
};
|
||||
|
@ -34,6 +34,9 @@
|
||||
|
||||
%name{Slic3r::Layer} class Layer {
|
||||
// owned by PrintObject, no constructor/destructor
|
||||
|
||||
Ref<Layer> as_layer()
|
||||
%code%{ RETVAL = THIS; %};
|
||||
|
||||
int id();
|
||||
void set_id(int id);
|
||||
|
Loading…
Reference in New Issue
Block a user