package Slic3r::SVG; use strict; use warnings; use SVG; use constant X => 0; use constant Y => 1; our $filltype = 'evenodd'; sub factor { return &Slic3r::SCALING_FACTOR * 10; } sub svg { my $svg = SVG->new(width => 200 * 10, height => 200 * 10); my $marker_end = $svg->marker( id => "endArrow", viewBox => "0 0 10 10", refX => "1", refY => "5", markerUnits => "strokeWidth", orient => "auto", markerWidth => "10", markerHeight => "8", ); $marker_end->polyline( points => "0,0 10,5 0,10 1,5", fill => "darkblue", ); return $svg; } sub output { my ($filename, @things) = @_; my $svg = svg(); my $arrows = 1; while (my $type = shift @things) { my $value = shift @things; if ($type eq 'no_arrows') { $arrows = 0; } elsif ($type =~ /^(?:(.+?)_)?expolygons$/) { my $colour = $1; $value = [ map $_->pp, @$value ]; my $g = $svg->group( style => { 'stroke-width' => 0, 'stroke' => $colour || 'black', 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')), 'fill-type' => $filltype, }, ); foreach my $expolygon (@$value) { my $points = join ' ', map "M $_ z", map join(" ", reverse map $_->[0]*factor() . " " . $_->[1]*factor(), @$_), @$expolygon; $g->path( d => $points, ); } } elsif ($type =~ /^(?:(.+?)_)?(polygon|polyline)s$/) { my ($colour, $method) = ($1, $2); $value = [ map $_->pp, @$value ]; my $g = $svg->group( style => { 'stroke-width' => ($method eq 'polyline') ? 1 : 0, 'stroke' => $colour || 'black', 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')), }, ); foreach my $polygon (@$value) { my $path = $svg->get_path( 'x' => [ map($_->[X] * factor(), @$polygon) ], 'y' => [ map($_->[Y] * factor(), @$polygon) ], -type => 'polygon', ); $g->$method( %$path, 'marker-end' => !$arrows ? "" : "url(#endArrow)", ); } } elsif ($type =~ /^(?:(.+?)_)?points$/) { my $colour = $1 // 'black'; my $r = $colour eq 'black' ? 1 : 3; $value = [ map $_->pp, @$value ]; my $g = $svg->group( style => { 'stroke-width' => 2, 'stroke' => $colour, 'fill' => $colour, }, ); foreach my $point (@$value) { $g->circle( cx => $point->[X] * factor(), cy => $point->[Y] * factor(), r => $r, ); } } elsif ($type =~ /^(?:(.+?)_)?lines$/) { my $colour = $1; $value = [ map $_->pp, @$value ]; my $g = $svg->group( style => { 'stroke-width' => 2, }, ); foreach my $line (@$value) { $g->line( x1 => $line->[0][X] * factor(), y1 => $line->[0][Y] * factor(), x2 => $line->[1][X] * factor(), y2 => $line->[1][Y] * factor(), style => { 'stroke' => $colour || 'black', }, 'marker-end' => !$arrows ? "" : "url(#endArrow)", ); } } } write_svg($svg, $filename); } sub write_svg { my ($svg, $filename) = @_; Slic3r::open(\my $fh, '>', $filename); print $fh $svg->xmlify; close $fh; printf "SVG written to %s\n", $filename; } 1;