SVG.pm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package Slic3r::SVG;
  2. use strict;
  3. use warnings;
  4. use SVG;
  5. use constant X => 0;
  6. use constant Y => 1;
  7. our $filltype = 'evenodd';
  8. sub factor {
  9. return &Slic3r::SCALING_FACTOR * 10;
  10. }
  11. sub svg {
  12. my $svg = SVG->new(width => 200 * 10, height => 200 * 10);
  13. my $marker_end = $svg->marker(
  14. id => "endArrow",
  15. viewBox => "0 0 10 10",
  16. refX => "1",
  17. refY => "5",
  18. markerUnits => "strokeWidth",
  19. orient => "auto",
  20. markerWidth => "10",
  21. markerHeight => "8",
  22. );
  23. $marker_end->polyline(
  24. points => "0,0 10,5 0,10 1,5",
  25. fill => "darkblue",
  26. );
  27. return $svg;
  28. }
  29. sub output {
  30. my ($filename, @things) = @_;
  31. my $svg = svg();
  32. my $arrows = 1;
  33. while (my $type = shift @things) {
  34. my $value = shift @things;
  35. if ($type eq 'no_arrows') {
  36. $arrows = 0;
  37. } elsif ($type =~ /^(?:(.+?)_)?expolygons$/) {
  38. my $colour = $1;
  39. $value = [ map $_->pp, @$value ];
  40. my $g = $svg->group(
  41. style => {
  42. 'stroke-width' => 0,
  43. 'stroke' => $colour || 'black',
  44. 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')),
  45. 'fill-type' => $filltype,
  46. },
  47. );
  48. foreach my $expolygon (@$value) {
  49. my $points = join ' ', map "M $_ z", map join(" ", reverse map $_->[0]*factor() . " " . $_->[1]*factor(), @$_), @$expolygon;
  50. $g->path(
  51. d => $points,
  52. );
  53. }
  54. } elsif ($type =~ /^(?:(.+?)_)?(polygon|polyline)s$/) {
  55. my ($colour, $method) = ($1, $2);
  56. $value = [ map $_->pp, @$value ];
  57. my $g = $svg->group(
  58. style => {
  59. 'stroke-width' => ($method eq 'polyline') ? 1 : 0,
  60. 'stroke' => $colour || 'black',
  61. 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')),
  62. },
  63. );
  64. foreach my $polygon (@$value) {
  65. my $path = $svg->get_path(
  66. 'x' => [ map($_->[X] * factor(), @$polygon) ],
  67. 'y' => [ map($_->[Y] * factor(), @$polygon) ],
  68. -type => 'polygon',
  69. );
  70. $g->$method(
  71. %$path,
  72. 'marker-end' => !$arrows ? "" : "url(#endArrow)",
  73. );
  74. }
  75. } elsif ($type =~ /^(?:(.+?)_)?points$/) {
  76. my $colour = $1 // 'black';
  77. my $r = $colour eq 'black' ? 1 : 3;
  78. $value = [ map $_->pp, @$value ];
  79. my $g = $svg->group(
  80. style => {
  81. 'stroke-width' => 2,
  82. 'stroke' => $colour,
  83. 'fill' => $colour,
  84. },
  85. );
  86. foreach my $point (@$value) {
  87. $g->circle(
  88. cx => $point->[X] * factor(),
  89. cy => $point->[Y] * factor(),
  90. r => $r,
  91. );
  92. }
  93. } elsif ($type =~ /^(?:(.+?)_)?lines$/) {
  94. my $colour = $1;
  95. $value = [ map $_->pp, @$value ];
  96. my $g = $svg->group(
  97. style => {
  98. 'stroke-width' => 2,
  99. },
  100. );
  101. foreach my $line (@$value) {
  102. $g->line(
  103. x1 => $line->[0][X] * factor(),
  104. y1 => $line->[0][Y] * factor(),
  105. x2 => $line->[1][X] * factor(),
  106. y2 => $line->[1][Y] * factor(),
  107. style => {
  108. 'stroke' => $colour || 'black',
  109. },
  110. 'marker-end' => !$arrows ? "" : "url(#endArrow)",
  111. );
  112. }
  113. }
  114. }
  115. write_svg($svg, $filename);
  116. }
  117. sub write_svg {
  118. my ($svg, $filename) = @_;
  119. Slic3r::open(\my $fh, '>', $filename);
  120. print $fh $svg->xmlify;
  121. close $fh;
  122. printf "SVG written to %s\n", $filename;
  123. }
  124. 1;