Skip to content

Commit

Permalink
Finished porting Slic3r::GCode to XS (speed boost!)
Browse files Browse the repository at this point in the history
  • Loading branch information
alranel committed Jul 2, 2015
1 parent 0ad4296 commit 3e739b8
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 167 deletions.
2 changes: 0 additions & 2 deletions lib/Slic3r.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
143 changes: 0 additions & 143 deletions lib/Slic3r/GCode.pm

This file was deleted.

2 changes: 1 addition & 1 deletion lib/Slic3r/GCode/PressureRegulator.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions lib/Slic3r/Print/GCode.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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) ;
}
}
}
Expand Down
171 changes: 168 additions & 3 deletions xs/src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "GCode.hpp"
#include "ExtrusionEntity.hpp"
#include <algorithm>
#include <cstdlib>

namespace Slic3r {

Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down
Loading

0 comments on commit 3e739b8

Please sign in to comment.