From 855ba9033262416de2ae9e27f55a21738ef5d70f Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 2 May 2013 11:42:51 +0200 Subject: [PATCH] New script to generate vertical section cuts from any given G-code file --- MANIFEST | 1 + lib/Slic3r/SVG.pm | 2 +- lib/Slic3r/Test.pm | 15 +++-- utils/gcode_sectioncut.pl | 133 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 utils/gcode_sectioncut.pl diff --git a/MANIFEST b/MANIFEST index 2bf6f4f93..2a6d0b81b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -78,6 +78,7 @@ t/support.t t/vibrationlimit.t utils/amf-to-stl.pl utils/file_info.pl +utils/gcode_sectioncut.pl utils/post-processing/filament-weight.pl utils/post-processing/prowl-notification.pl utils/post-processing/z-every-line.pl diff --git a/lib/Slic3r/SVG.pm b/lib/Slic3r/SVG.pm index 0ac286395..a79094854 100644 --- a/lib/Slic3r/SVG.pm +++ b/lib/Slic3r/SVG.pm @@ -9,7 +9,7 @@ use constant Y => 1; our $filltype = 'evenodd'; -sub factor { +sub factor {return 30; return &Slic3r::SCALING_FACTOR * 10; } diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm index 0884fd308..a059313fa 100644 --- a/lib/Slic3r/Test.pm +++ b/lib/Slic3r/Test.pm @@ -94,7 +94,7 @@ sub parse { my $self = shift; my ($cb) = @_; - foreach my $line (split /\n/, $self->gcode) { + foreach my $line (split /\R+/, $self->gcode) { print "$line\n" if $Verbose || $ENV{SLIC3R_TESTS_GCODE}; $line =~ s/\s*;(.*)//; # strip comment next if $line eq ''; @@ -107,15 +107,14 @@ sub parse { # check retraction if ($command =~ /^G[01]$/) { - if (!exists $args{E}) { - $info{travel} = 1; - } foreach my $axis (@AXES) { - if (!exists $args{$axis}) { + if (exists $args{$axis}) { + $info{"dist_$axis"} = $args{$axis} - $self->$axis; + $info{"new_$axis"} = $args{$axis}; + } else { $info{"dist_$axis"} = 0; - next; + $info{"new_$axis"} = $self->$axis; } - $info{"dist_$axis"} = $args{$axis} - $self->$axis; } $info{dist_XY} = Slic3r::Line->new([0,0], [@info{qw(dist_X dist_Y)}])->length; if (exists $args{E}) { @@ -124,6 +123,8 @@ sub parse { } elsif ($info{dist_E} < 0) { $info{retracting} = 1 } + } else { + $info{travel} = 1; } } diff --git a/utils/gcode_sectioncut.pl b/utils/gcode_sectioncut.pl new file mode 100644 index 000000000..39d94112b --- /dev/null +++ b/utils/gcode_sectioncut.pl @@ -0,0 +1,133 @@ +#!/usr/bin/perl +# This script generates section cuts from a given G-Code file + +use strict; +use warnings; + +BEGIN { + use FindBin; + use lib "$FindBin::Bin/../lib"; +} + +use Getopt::Long qw(:config no_auto_abbrev); +use IO::All; +use List::Util qw(max); +use Slic3r; +use Slic3r::Geometry qw(X Y A B X1 Y1 X2 Y2); +use Slic3r::Geometry::Clipper qw(JT_SQUARE); +use Slic3r::Test; +use SVG; + +my %opt = ( + layer_height => 0.2, + extrusion_width => 0.5, + scale => 30, +); +{ + my %options = ( + 'help' => sub { usage() }, + 'layer-height|h=f' => \$opt{layer_height}, + 'extrusion-width|w=f' => \$opt{extrusion_width}, + 'scale|s=i' => \$opt{scale}, + ); + GetOptions(%options) or usage(1); + $ARGV[0] or usage(1); +} + +{ + my $input_file = $ARGV[0]; + my $output_file = $input_file; + $output_file =~ s/\.(?:gcode|gco|ngc|g)$/.svg/; + + # read paths + my %paths = (); # z => [ path, path ... ] + Slic3r::Test::GCodeReader->new(gcode => io($input_file)->all)->parse(sub { + my ($self, $cmd, $args, $info) = @_; + + if ($cmd eq 'G1' && $info->{extruding}) { + $paths{ $self->Z } ||= []; + push @{ $paths{ $self->Z } }, Slic3r::Line->new( + [ $self->X, $self->Y ], + [ $info->{new_X}, $info->{new_Y} ], + ); + } + }); + + # calculate print extents + my @bounding_box = Slic3r::Geometry::bounding_box([ map @$_, map @$_, values %paths ]); + my @size = ( + ($bounding_box[X2] - $bounding_box[X1]), + ($bounding_box[Y2] - $bounding_box[Y1]), + ); + + # calculate section line + my $section_y = ($bounding_box[Y2] + $bounding_box[Y1]) / 2; + my $section_line = [ + [ $bounding_box[X1], $section_y ], + [ $bounding_box[X2], $section_y ], + ]; + + # initialize output + my $max_z = max(keys %paths); + my $svg = SVG->new( + width => $opt{scale} * $size[X], + height => $opt{scale} * $max_z, + ); + + # put everything into a group + my $g = $svg->group(style => { + 'stroke-width' => 1, + 'stroke' => '#444444', + 'fill' => 'grey', + }); + + # draw paths + foreach my $z (sort keys %paths) { + foreach my $line (@{ $paths{$z} }) { + my @intersections = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( + Slic3r::ExPolygon->new(_grow($line, $opt{extrusion_width}/2)), + [ $section_line ], + ) }; + + $g->rectangle( + 'x' => $opt{scale} * ($_->[A][X] - $bounding_box[X1]), + 'y' => $opt{scale} * ($max_z - $z), + 'width' => $opt{scale} * abs($_->[B][X] - $_->[A][X]), + 'height' => $opt{scale} * $opt{layer_height}, + 'rx' => $opt{scale} * $opt{layer_height} * 0.35, + 'ry' => $opt{scale} * $opt{layer_height} * 0.35, + ) for @intersections; + } + } + + # write output + Slic3r::open(\my $fh, '>', $output_file); + print $fh $svg->xmlify; + close $fh; + printf "Section cut SVG written to %s\n", $output_file; +} + +# replace built-in Line->grow method which relies on int_offset() +sub _grow { + my ($line, $distance) = @_; + + my $polygon = [ @$line, CORE::reverse @$line[1..($#$line-1)] ]; + return @{Math::Clipper::offset([$polygon], $distance, 100000, JT_SQUARE, 2)}; +} + +sub usage { + my ($exit_code) = @_; + + print <<"EOF"; +Usage: gcode_sectioncut.pl [ OPTIONS ] file.gcode + + --help Output this usage screen and exit + --layer-height, -h Use the specified layer height + --extrusion-width, -w Use the specified extrusion width + --scale Factor for converting G-code units to SVG units + +EOF + exit ($exit_code || 0); +} + +__END__