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   873 use v5.12;
  19         64  
2 19     19   97 use warnings;
  19         26  
  19         770  
3              
4             # logic of value hash keys for all color spacs
5              
6             package Graphics::Toolkit::Color::Space::Shape;
7 19     19   122 use Graphics::Toolkit::Color::Space::Basis;
  19         130  
  19         555  
8 19     19   4520 use Graphics::Toolkit::Color::Space::Util ':all';
  19         39  
  19         3068  
9 19     19   135 use Carp;
  19         41  
  19         30497  
10              
11             sub new {
12 298     298 0 2001 my $pkg = shift;
13 298         508 my ($basis, $range, $type) = @_;
14 298 100       627 return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis';
15              
16 297 100 100     1420 if (not defined $range or $range eq 'normal'){ # check range settings
    100 66        
    100 100        
17 220         571 $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         25 $range = int $range;
21 16         70 $range = [([0, $range]) x $basis->count];
22              
23             } elsif (ref $range eq 'ARRAY' and @$range == $basis->count ) { # full range def
24 56         132 for my $i ($basis->iterator) {
25 168         225 my $drange = $range->[$i]; # range def of this dimension
26              
27 168 100 66     813 if (not ref $drange and $drange > 0){
    100 66        
      66        
      66        
      66        
28 110         134 $drange = int $drange;
29 110         226 $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         19 } else { return }
35              
36              
37 289 100 100     1047 if (not defined $type){ $type = [ (1) x $basis->count ] } # default is all linear space
  36 100       84  
38             elsif (ref $type eq 'ARRAY' and @$type == $basis->count ) {
39 250         456 for my $i ($basis->iterator) {
40 752         943 my $dtype = $type->[$i]; # type def of this dimension
41 752 50       1123 return unless defined $dtype;
42 752 100 100     3177 if ($dtype eq 'angle' or $dtype eq 'circular' or $dtype eq '0') { $type->[$i] = 0 }
  173 100 100     287  
      100        
43 577         885 elsif ($dtype eq 'linear' or $dtype eq '1') { $type->[$i] = 1 }
44 2         9 else { return }
45             }
46 3         23 } else { return }
47              
48 284         1098 bless { basis => $basis, range => $range, type => $type }
49             }
50              
51 4576     4576 0 9121 sub basis { $_[0]{'basis'}}
52             sub dimension_is_int {
53 3219     3219 0 4705 my ($self, $dnr, $range) = @_;
54 3219   33     5019 $range //= $self->{'range'};
55 3219 50 33     9132 return undef unless ref $range eq 'ARRAY' and exists $range->[$dnr];
56 3219         4001 my $r = $range->[$dnr];
57 3219 100 100     9002 return 0 if $r->[0] == 0 and $r->[1] == 1; #normal
58 2506 100       4148 return 0 if int($r->[0]) != $r->[0];
59 2482 50       3891 return 0 if int($r->[1]) != $r->[1];
60 2482         6853 1;
61             }
62             sub _range {
63 1454     1454   2343 my ($self, $external_range) = @_;
64 1454 100       3276 return $self->{'range'} unless defined $external_range;
65              
66             # check if range def is valid and eval (exapand) it
67 217         506 $external_range = Graphics::Toolkit::Color::Space::Shape->new( $self->{'basis'}, $external_range, $self->{'type'});
68 217 100       791 return (ref $external_range) ? $external_range->{'range'} : undef ;
69             }
70              
71             ########################################################################
72              
73             sub delta { # values have to be normalized
74 114     114 0 6051 my ($self, $values1, $values2) = @_;
75 114 100 100     190 return unless $self->basis->is_array( $values1 ) and $self->basis->is_array( $values2 );
76 108         235 my @delta = map {$values2->[$_] - $values1->[$_] } $self->basis->iterator;
  326         616  
77 108 100       210 map { $self->{'type'}[$_] ? $delta[$_] :
  326 100       882  
    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 2937 my ($self, $values, $range) = @_;
84 288 100       551 return carp 'color value vector in '.$self->basis->name.' needs '.$self->basis->count.' values'
85             unless $self->basis->is_array( $values );
86 263         583 $range = $self->_range( $range );
87 263 50       616 return carp "bad range definition" unless ref $range;
88 263         457 my @names = $self->basis->keys;
89 263         507 for my $i ($self->basis->iterator){
90 708 100       1790 return carp $names[$i]." value is below minimum of ".$range->[$i][0] if $values->[$i] < $range->[$i][0];
91 672 100       1544 return carp $names[$i]." value is above maximum of ".$range->[$i][1] if $values->[$i] > $range->[$i][1];
92 636 100 100     1034 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         714 return;
96             }
97              
98             sub clamp {
99 260     260 0 8885 my ($self, $values, $range) = @_;
100 260         501 $range = $self->_range( $range );
101 260 100       607 return undef, carp "bad range definition, need upper limit, 2 element ARRAY or ARRAY of 2 element ARRAYs" unless ref $range;
102 259 50       565 $values = [] unless ref $values eq 'ARRAY';
103 259         585 push @$values, 0 while @$values < $self->basis->count;
104 259         574 pop @$values while @$values > $self->basis->count;
105 259         442 for my $i ($self->basis->iterator){
106 782         1232 my $delta = $range->[$i][1] - $range->[$i][0];
107 782 100       1318 if ($self->{'type'}[$i]){
108 650 100       1179 $values->[$i] = $range->[$i][0] if $values->[$i] < $range->[$i][0];
109 650 100       1243 $values->[$i] = $range->[$i][1] if $values->[$i] > $range->[$i][1];
110             } else {
111 132         300 $values->[$i] += $delta while $values->[$i] < $range->[$i][0];
112 132         276 $values->[$i] -= $delta while $values->[$i] > $range->[$i][1];
113 132 100       256 $values->[$i] = $range->[$i][0] if $values->[$i] == $range->[$i][1];
114             }
115 782 100       1271 $values->[$i] = round($values->[$i]) if $self->dimension_is_int($i, $range);
116             }
117 259         1025 return @$values;
118             }
119              
120             ########################################################################
121              
122             sub normalize {
123 237     237 0 5252 my ($self, $values, $range) = @_;
124 237 50       378 return unless $self->basis->is_array( $values );
125 237         493 $range = $self->_range( $range );
126 237 50       446 return carp "bad range definition" unless ref $range;
127 237         408 map { ($values->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  712         1885  
128             }
129              
130             sub denormalize {
131 600     600 0 9650 my ($self, $values, $range) = @_;
132 600 50       1030 return unless $self->basis->is_array( $values );
133 600         1225 $range = $self->_range( $range );
134 600 100       1209 return carp "bad range definition" unless ref $range;
135 599         1044 my @val = map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0] } $self->basis->iterator;
  1801         4333  
136 599 100       1107 @val = map { $self->dimension_is_int($_, $range) ? round ($val[$_]) : $val[$_] } $self->basis->iterator;
  1801         2796  
137 599         1969 return @val;
138             }
139              
140             sub denormalize_range {
141 94     94 0 164 my ($self, $values, $range) = @_;
142 94 50       148 return unless $self->basis->is_array( $values );
143 94         189 $range = $self->_range( $range );
144 94 50       197 return carp "bad range definition" unless ref $range;
145 94         163 map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  283         629  
146             }
147              
148             1;