File Coverage

lib/Graphics/Toolkit/Color/Space/Shape.pm
Criterion Covered Total %
statement 105 105 100.0
branch 70 80 87.5
condition 41 51 80.3
subroutine 15 15 100.0
pod 0 9 0.0
total 231 260 88.8


line stmt bran cond sub pod time code
1 19     19   865 use v5.12;
  19         58  
2 19     19   108 use warnings;
  19         34  
  19         756  
3              
4             # logic of value hash keys for all color spacs
5              
6             package Graphics::Toolkit::Color::Space::Shape;
7 19     19   107 use Graphics::Toolkit::Color::Space::Basis;
  19         34  
  19         523  
8 19     19   4286 use Graphics::Toolkit::Color::Space::Util ':all';
  19         40  
  19         2848  
9 19     19   168 use Carp;
  19         35  
  19         29856  
10              
11             sub new {
12 298     298 0 1869 my $pkg = shift;
13 298         530 my ($basis, $range, $type) = @_;
14 298 100       648 return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis';
15              
16 297 100 100     1389 if (not defined $range or $range eq 'normal'){ # check range settings
    100 66        
    100 100        
17 220         557 $range = [([0,1]) x $basis->count]; # default range = normal range
18              
19             } elsif (not ref $range and $range > 0) { # single int range def
20 16         27 $range = int $range;
21 16         57 $range = [([0, $range]) x $basis->count];
22              
23             } elsif (ref $range eq 'ARRAY' and @$range == $basis->count ) { # full range def
24 56         134 for my $i ($basis->iterator) {
25 168         229 my $drange = $range->[$i]; # range def of this dimension
26              
27 168 100 66     959 if (not ref $drange and $drange > 0){
    100 66        
      66        
      66        
      66        
28 110         141 $drange = int $drange;
29 110         224 $range->[$i] = [0, $drange];
30             } elsif (ref $drange eq 'ARRAY' and @$drange == 2
31             and defined $drange->[0] and defined $drange->[1] and $drange->[0] < $drange->[1]) { # full valid def
32 3         13 } else { return }
33             }
34 5         20 } else { return }
35              
36              
37 289 100 100     1005 if (not defined $type){ $type = [ (1) x $basis->count ] } # default is all linear space
  36 100       83  
38             elsif (ref $type eq 'ARRAY' and @$type == $basis->count ) {
39 250         440 for my $i ($basis->iterator) {
40 752         884 my $dtype = $type->[$i]; # type def of this dimension
41 752 50       1099 return unless defined $dtype;
42 752 100 100     3199 if ($dtype eq 'angle' or $dtype eq 'circular' or $dtype eq '0') { $type->[$i] = 0 }
  173 100 100     292  
      100        
43 577         839 elsif ($dtype eq 'linear' or $dtype eq '1') { $type->[$i] = 1 }
44 2         10 else { return }
45             }
46 3         13 } else { return }
47              
48 284         1055 bless { basis => $basis, range => $range, type => $type }
49             }
50              
51 4576     4576 0 9167 sub basis { $_[0]{'basis'}}
52             sub dimension_is_int {
53 3219     3219 0 4345 my ($self, $dnr, $range) = @_;
54 3219   33     4860 $range //= $self->{'range'};
55 3219 50 33     8589 return undef unless ref $range eq 'ARRAY' and exists $range->[$dnr];
56 3219         3834 my $r = $range->[$dnr];
57 3219 100 100     8512 return 0 if $r->[0] == 0 and $r->[1] == 1; #normal
58 2506 100       3842 return 0 if int($r->[0]) != $r->[0];
59 2482 50       3591 return 0 if int($r->[1]) != $r->[1];
60 2482         6234 1;
61             }
62             sub _range {
63 1454     1454   2104 my ($self, $external_range) = @_;
64 1454 100       3203 return $self->{'range'} unless defined $external_range;
65              
66             # check if range def is valid and eval (exapand) it
67 217         495 $external_range = Graphics::Toolkit::Color::Space::Shape->new( $self->{'basis'}, $external_range, $self->{'type'});
68 217 100       723 return (ref $external_range) ? $external_range->{'range'} : undef ;
69             }
70              
71             ########################################################################
72              
73             sub delta { # values have to be normalized
74 114     114 0 6077 my ($self, $values1, $values2) = @_;
75 114 100 100     207 return unless $self->basis->is_array( $values1 ) and $self->basis->is_array( $values2 );
76 108         237 my @delta = map {$values2->[$_] - $values1->[$_] } $self->basis->iterator;
  326         606  
77 108 100       202 map { $self->{'type'}[$_] ? $delta[$_] :
  326 100       857  
    100          
78             $delta[$_] < -0.5 ? ($delta[$_]+1) :
79             $delta[$_] > 0.5 ? ($delta[$_]-1) : $delta[$_] } $self->basis->iterator;
80             }
81              
82             sub check {
83 288     288 0 2808 my ($self, $values, $range) = @_;
84 288 100       529 return carp 'color value vector in '.$self->basis->name.' needs '.$self->basis->count.' values'
85             unless $self->basis->is_array( $values );
86 263         568 $range = $self->_range( $range );
87 263 50       542 return carp "bad range definition" unless ref $range;
88 263         427 my @names = $self->basis->keys;
89 263         473 for my $i ($self->basis->iterator){
90 708 100       1681 return carp $names[$i]." value is below minimum of ".$range->[$i][0] if $values->[$i] < $range->[$i][0];
91 672 100       1721 return carp $names[$i]." value is above maximum of ".$range->[$i][1] if $values->[$i] > $range->[$i][1];
92 636 100 100     967 return carp $names[$i]." value has to be an integer" if $self->dimension_is_int($i, $range)
93             and int $values->[$i] != $values->[$i];
94             }
95 175         599 return;
96             }
97              
98             sub clamp {
99 260     260 0 8960 my ($self, $values, $range) = @_;
100 260         507 $range = $self->_range( $range );
101 260 100       557 return undef, carp "bad range definition, need upper limit, 2 element ARRAY or ARRAY of 2 element ARRAYs" unless ref $range;
102 259 50       502 $values = [] unless ref $values eq 'ARRAY';
103 259         616 push @$values, 0 while @$values < $self->basis->count;
104 259         626 pop @$values while @$values > $self->basis->count;
105 259         450 for my $i ($self->basis->iterator){
106 782         1181 my $delta = $range->[$i][1] - $range->[$i][0];
107 782 100       1328 if ($self->{'type'}[$i]){
108 650 100       1157 $values->[$i] = $range->[$i][0] if $values->[$i] < $range->[$i][0];
109 650 100       1096 $values->[$i] = $range->[$i][1] if $values->[$i] > $range->[$i][1];
110             } else {
111 132         330 $values->[$i] += $delta while $values->[$i] < $range->[$i][0];
112 132         276 $values->[$i] -= $delta while $values->[$i] > $range->[$i][1];
113 132 100       310 $values->[$i] = $range->[$i][0] if $values->[$i] == $range->[$i][1];
114             }
115 782 100       1203 $values->[$i] = round($values->[$i]) if $self->dimension_is_int($i, $range);
116             }
117 259         993 return @$values;
118             }
119              
120             ########################################################################
121              
122             sub normalize {
123 237     237 0 4666 my ($self, $values, $range) = @_;
124 237 50       363 return unless $self->basis->is_array( $values );
125 237         441 $range = $self->_range( $range );
126 237 50       509 return carp "bad range definition" unless ref $range;
127 237         373 map { ($values->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  712         1849  
128             }
129              
130             sub denormalize {
131 600     600 0 7395 my ($self, $values, $range) = @_;
132 600 50       980 return unless $self->basis->is_array( $values );
133 600         1153 $range = $self->_range( $range );
134 600 100       1140 return carp "bad range definition" unless ref $range;
135 599         966 my @val = map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0] } $self->basis->iterator;
  1801         3897  
136 599 100       1091 @val = map { $self->dimension_is_int($_, $range) ? round ($val[$_]) : $val[$_] } $self->basis->iterator;
  1801         2593  
137 599         1770 return @val;
138             }
139              
140             sub denormalize_range {
141 94     94 0 137 my ($self, $values, $range) = @_;
142 94 50       137 return unless $self->basis->is_array( $values );
143 94         164 $range = $self->_range( $range );
144 94 50       203 return carp "bad range definition" unless ref $range;
145 94         144 map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  283         609  
146             }
147              
148             1;