diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 9dc4e29bd..5ebca1db9 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -344,7 +344,7 @@ sub travel_to { if ($travel->length < scale $self->config->get_at('retract_before_travel', $self->writer->extruder->id) || ($self->config->only_retract_when_crossing_perimeters && $self->config->fill_density > 0 - && $self->layer->any_internal_region_slice_contains_line($travel)) + && defined($self->layer) && $self->layer->any_internal_region_slice_contains_line($travel)) || (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands->contains_line($travel)) ) { # Just perform a straight travel move without any retraction. diff --git a/utils/wireframe.pl b/utils/wireframe.pl index ad5a27753..053581dec 100644 --- a/utils/wireframe.pl +++ b/utils/wireframe.pl @@ -11,14 +11,15 @@ BEGIN { } use Getopt::Long qw(:config no_auto_abbrev); -use PDF::API2; use Slic3r; use Slic3r::ExtrusionPath ':roles'; -use Slic3r::Geometry qw(scale unscale X Y); +use Slic3r::Geometry qw(scale unscale X Y PI); my %opt = ( - step_height => 10, - first_layer_height => 0.3, + step_height => 5, + nozzle_angle => 30, + nozzle_width => 10, + first_layer_height => 0.3, ); { my %options = ( @@ -30,13 +31,15 @@ my %opt = ( 'first-layer-height=f' => \$opt{first_layer_height}, ); GetOptions(%options) or usage(1); - $opt{output_file} or usage(1);ì + $opt{output_file} or usage(1); $ARGV[0] or usage(1); } { # load model my $model = Slic3r::Model->read_from_file($ARGV[0]); + $model->add_default_instances; + $model->center_instances_around_point(Slic3r::Pointf->new(100,100)); my $mesh = $model->mesh; $mesh->translate(0, 0, -$mesh->bounding_box->z_min); @@ -46,6 +49,7 @@ my %opt = ( for (my $z = $opt{first_layer_height}; $z <= $z_max; $z += $opt{step_height}) { push @z, $z; } + my @slices = @{$mesh->slice(\@z)}; my $flow = Slic3r::Flow->new( width => 0.35, @@ -54,45 +58,96 @@ my %opt = ( bridge => 1, ); - my $section; - - # build a square section - { - my $dist = 2 * $opt{step_height}; # horizontal step - my $side_modules = 3; - my @points = ( - [0,0], - (map [$_*$dist, 0], 1..$side_modules), - (map [$side_modules*$dist, $_*$dist], 1..$side_modules), - (map [($_-1)*$dist, $side_modules*$dist], reverse 1..$side_modules), - (map [0, ($_-1)*$dist], reverse 1..$side_modules), - ); - pop @points; # prevent coinciding endpoints - $section = Slic3r::Polygon->new_scale(@points); - } - my $section_loop = Slic3r::ExtrusionLoop->new_from_paths( - Slic3r::ExtrusionPath->new( - polyline => $section->split_at_first_point, - role => EXTR_ROLE_BRIDGE, - mm3_per_mm => $flow->mm3_per_mm, - width => $flow->width, - height => $flow->height, - ) - ); - - my $vertical_steps = 3; + my $config = Slic3r::Config::Print->new; + $config->set('gcode_comments', 1); open my $fh, '>', $opt{output_file}; my $gcodegen = Slic3r::GCode->new( enable_loop_clipping => 0, # better bonding ); + $gcodegen->apply_print_config($config); $gcodegen->set_extruders([0]); print $fh $gcodegen->set_extruder(0); print $fh $gcodegen->writer->preamble; - foreach my $z (map $_*$opt{step_height}, 0..($vertical_steps-1)) { - print $fh $gcodegen->writer->travel_to_z($z + $flow->height); - print $fh $gcodegen->extrude_loop($section_loop, "contour"); + my $e = $gcodegen->writer->extruder->e_per_mm3 * $flow->mm3_per_mm; + + foreach my $layer_id (0..$#z) { + my $z = $z[$layer_id]; + + foreach my $island (@{$slices[$layer_id]}) { + foreach my $polygon (@$island) { + if ($layer_id > 0) { + # find the lower polygon that we want to connect to this one + my $lower = $slices[$layer_id-1]->[0]->contour; # 't was easy, wasn't it? + my $lower_z = $z[$layer_id-1]; + + { + my @points = (); + + # keep all points with strong angles + { + my @pp = @$polygon; + foreach my $i (0..$#pp) { + push @points, $pp[$i-1] if abs($pp[$i-1]->ccw_angle($pp[$i-2], $pp[$i]) - PI) > PI/3; + } + } + + $polygon = Slic3r::Polygon->new(@points); + } + #$polygon = Slic3r::Polygon->new(@{$polygon->split_at_first_point->equally_spaced_points(scale $opt{nozzle_width})}); + + # find vertical lines + my @vertical = (); + foreach my $point (@{$polygon}) { + push @vertical, Slic3r::Line->new($point->projection_onto_polygon($lower), $point); + } + + next if !@vertical; + + my @points = (); + foreach my $line (@vertical) { + push @points, Slic3r::Pointf3->new( + unscale($line->a->x), + unscale($line->a->y), #)) + $lower_z, + ); + push @points, Slic3r::Pointf3->new( + unscale($line->b->x), + unscale($line->b->y), #)) + $z, + ); + } + + # reappend first point as destination of the last diagonal segment + push @points, Slic3r::Pointf3->new( + unscale($vertical[0]->a->x), + unscale($vertical[0]->a->y), #)) + $lower_z, + ); + + # move to the position of the first vertical line + print $fh $gcodegen->writer->travel_to_xyz(shift @points); + + # extrude segments + foreach my $point (@points) { + print $fh $gcodegen->writer->extrude_to_xyz($point, $e * $gcodegen->writer->get_position->distance_to($point)); + } + } + } + + print $fh $gcodegen->writer->travel_to_z($z); + foreach my $polygon (@$island) { + #my $polyline = $polygon->split_at_vertex(Slic3r::Point->new_scale(@{$gcodegen->writer->get_position}[0,1])); + my $polyline = $polygon->split_at_first_point; + print $fh $gcodegen->writer->travel_to_xy(Slic3r::Pointf->new_unscale(@{ $polyline->first_point }), "move to first contour point"); + + foreach my $line (@{$polyline->lines}) { + my $point = Slic3r::Pointf->new_unscale(@{ $line->b }); + print $fh $gcodegen->writer->extrude_to_xy($point, $e * unscale($line->length)); + } + } + } } close $fh; diff --git a/xs/src/libslic3r/GCodeWriter.cpp b/xs/src/libslic3r/GCodeWriter.cpp index c36ca4f45..bb8035ac3 100644 --- a/xs/src/libslic3r/GCodeWriter.cpp +++ b/xs/src/libslic3r/GCodeWriter.cpp @@ -491,6 +491,12 @@ GCodeWriter::unlift() return gcode; } +Pointf3 +GCodeWriter::get_position() const +{ + return this->_pos; +} + #ifdef SLIC3RXS REGISTER_CLASS(GCodeWriter, "GCode::Writer"); #endif diff --git a/xs/src/libslic3r/GCodeWriter.hpp b/xs/src/libslic3r/GCodeWriter.hpp index 5500a19f5..03de197d1 100644 --- a/xs/src/libslic3r/GCodeWriter.hpp +++ b/xs/src/libslic3r/GCodeWriter.hpp @@ -45,6 +45,7 @@ class GCodeWriter { std::string unretract(); std::string lift(); std::string unlift(); + Pointf3 get_position() const; private: std::string _extrusion_axis; diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp index 4eee03eff..77f4224d5 100644 --- a/xs/src/libslic3r/Point.cpp +++ b/xs/src/libslic3r/Point.cpp @@ -161,10 +161,15 @@ Point::ccw(const Line &line) const } // returns the CCW angle between this-p1 and this-p2 +// i.e. this assumes a CCW rotation from p1 to p2 around this double Point::ccw_angle(const Point &p1, const Point &p2) const { - return Line(*this, p1).orientation() - Line(*this, p2).orientation(); + double angle = atan2(p1.x - this->x, p1.y - this->y) + - atan2(p2.x - this->x, p2.y - this->y); + + // we only want to return only positive angles + return angle <= 0 ? angle + 2*PI : angle; } Point diff --git a/xs/xsp/GCodeWriter.xsp b/xs/xsp/GCodeWriter.xsp index ee9049e56..a76c0e55f 100644 --- a/xs/xsp/GCodeWriter.xsp +++ b/xs/xsp/GCodeWriter.xsp @@ -44,6 +44,7 @@ std::string unretract(); std::string lift(); std::string unlift(); + Clone get_position() const; %{ SV* diff --git a/xs/xsp/Point.xsp b/xs/xsp/Point.xsp index 3b244fe55..e45c41213 100644 --- a/xs/xsp/Point.xsp +++ b/xs/xsp/Point.xsp @@ -31,6 +31,8 @@ %code{% RETVAL = THIS->distance_to(*line); %}; double ccw(Point* p1, Point* p2) %code{% RETVAL = THIS->ccw(*p1, *p2); %}; + double ccw_angle(Point* p1, Point* p2) + %code{% RETVAL = THIS->ccw_angle(*p1, *p2); %}; Clone projection_onto_polygon(Polygon* polygon) %code{% RETVAL = new Point(THIS->projection_onto(*polygon)); %}; Clone projection_onto_polyline(Polyline* polyline)