File Coverage

lib/SVG/Estimate/Polyline.pm
Criterion Covered Total %
statement 42 42 100.0
branch 13 14 92.8
condition n/a
subroutine 5 5 100.0
pod 0 1 0.0
total 60 62 96.7


line stmt bran cond sub pod time code
1             package SVG::Estimate::Polyline;
2             $SVG::Estimate::Polyline::VERSION = '1.0113';
3 16     16   6501 use Moo;
  16         31  
  16         76  
4 16     16   5013 use Clone qw/clone/;
  16         3957  
  16         673  
5 16     16   85 use List::Util qw/pairs/;
  16         20  
  16         8733  
6              
7             extends 'SVG::Estimate::Shape';
8             with 'SVG::Estimate::Role::Pythagorean';
9              
10             =head1 NAME
11              
12             SVG::Estimate::Polyline - Handles estimating multi-part lines.
13              
14             =head1 VERSION
15              
16             version 1.0113
17              
18             =head1 SYNOPSIS
19              
20             my $line = SVG::Estimate::Polyline->new(
21             transformer => $transform,
22             start_point => [45,13],
23             points => '20,20 40,25 60,40 80,120 120,140 200,180',
24             );
25              
26             my $length = $line->length;
27              
28             =head1 INHERITANCE
29              
30             This class extends L and consumes L.
31              
32             =head1 METHODS
33              
34             =head2 new()
35              
36             Constructor.
37              
38             =over
39              
40             =item points
41              
42             A string listing points for the polyline as defined by L.
43              
44             =back
45              
46             =cut
47              
48             has points => (
49             is => 'ro',
50             required => 1,
51             );
52              
53             =head2 parsed_points()
54              
55             Returns an array reference of array references marking the parsed C string.
56              
57             =cut
58              
59             has parsed_points => (
60             is => 'ro',
61             lazy => 1,
62             default => sub {
63             return [];
64             },
65             );
66              
67             ##Blatantly stolen from Image::SVG::Path
68              
69             # Match the e or E in an exponent.
70              
71             my $e = qr/[eE]/;
72              
73             # These regular expressions are directly taken from the SVG grammar,
74             # https://www.w3.org/TR/SVG/paths.html#PathDataBNF
75              
76             our $sign = qr/\+|\-/;
77              
78             our $wsp = qr/[\x20\x09\x0D\x0A]/;
79              
80             our $comma_wsp = qr/(?:$wsp+,?$wsp*|,$wsp*)/;
81              
82             # The following regular expression splits the path into pieces Note we
83             # only split on '-' or '+' when not preceeded by 'e'. This regular
84             # expression is not following the SVG grammar, it is going our own
85             # way.
86              
87             my $split_re = qr/
88             (?:
89             $wsp*,$wsp*
90             |
91             (?
92             |
93             (?
94             |
95             $wsp+
96             )
97             /x;
98              
99             sub BUILDARGS {
100 23     23 0 42684 my ($class, @args) = @_;
101             ##Upgrade to hashref
102 23 50       111 my $args = @args % 2 ? $args[0] : { @args };
103 23         271 my @pairs = $class->_get_pairs($args->{points});
104 23         48 my ($min_x, $max_x, $min_y, $max_y) = (1e10, -1e10, 1e10, -1e10);
105 23         29 my $first = 1;
106 23         37 my $start = [];
107 23         31 my $length = 0;
108 23         45 PAIR: foreach my $point (@pairs) {
109 280 100       484 if ($args->{transformer}->has_transforms) {
110 20         37 $point = $args->{transformer}->transform($point);
111             }
112 280 100       3518 $min_x = $point->[0] if $point->[0] < $min_x;
113 280 100       384 $max_x = $point->[0] if $point->[0] > $max_x;
114 280 100       448 $min_y = $point->[1] if $point->[1] < $min_y;
115 280 100       384 $max_y = $point->[1] if $point->[1] > $max_y;
116 280 100       325 if ($first) {
117 23         32 $first = 0;
118 23         43 $start = $point;
119 23         71 next PAIR;
120             }
121 257         435 $length += $class->pythagorean($start, $point);
122 257         300 $start = $point;
123             }
124 23         57 $args->{parsed_points} = \@pairs;
125 23         54 $args->{min_x} = $min_x;
126 23         38 $args->{max_x} = $max_x;
127 23         42 $args->{min_y} = $min_y;
128 23         59 $args->{max_y} = $max_y;
129 23         193 $args->{draw_start} = clone $pairs[0];
130 23         119 $args->{draw_end} = clone $pairs[-1];
131 23         58 $args->{shape_length} = $length;
132 23         474 return $args;
133             }
134              
135             ##This method is here so that Polygon can wrap it to add a closing point.
136              
137             sub _get_pairs {
138 23     23   47 my ($class, $string) = @_;
139 23         1282 my @points = split $split_re, $string;
140 23         311 my @pairs = pairs @points;
141 23         105 return @pairs;
142             }
143              
144             1;