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 17     17   872 use v5.12;
  17         67  
2 17     17   89 use warnings;
  17         29  
  17         681  
3              
4             # logic of value hash keys for all color spacs
5              
6             package Graphics::Toolkit::Color::Space::Shape;
7 17     17   94 use Graphics::Toolkit::Color::Space::Basis;
  17         35  
  17         490  
8 17     17   4522 use Graphics::Toolkit::Color::Space::Util ':all';
  17         38  
  17         2625  
9 17     17   127 use Carp;
  17         30  
  17         28057  
10              
11             sub new {
12 288     288 0 1690 my $pkg = shift;
13 288         483 my ($basis, $range, $type) = @_;
14 288 100       640 return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis';
15              
16 287 100 100     1329 if (not defined $range or $range eq 'normal'){ # check range settings
    100 66        
    100 100        
17 212         580 $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         28 $range = int $range;
21 16         62 $range = [([0, $range]) x $basis->count];
22              
23             } elsif (ref $range eq 'ARRAY' and @$range == $basis->count ) { # full range def
24 54         123 for my $i ($basis->iterator) {
25 162         225 my $drange = $range->[$i]; # range def of this dimension
26              
27 162 100 66     951 if (not ref $drange and $drange > 0){
    100 66        
      66        
      66        
      66        
28 108         141 $drange = int $drange;
29 108         232 $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         14 } else { return }
33             }
34 5         18 } else { return }
35              
36              
37 279 100 100     1086 if (not defined $type){ $type = [ (1) x $basis->count ] } # default is all linear space
  34 100       78  
38             elsif (ref $type eq 'ARRAY' and @$type == $basis->count ) {
39 242         455 for my $i ($basis->iterator) {
40 728         887 my $dtype = $type->[$i]; # type def of this dimension
41 728 50       1128 return unless defined $dtype;
42 728 100 100     3177 if ($dtype eq 'angle' or $dtype eq 'circular' or $dtype eq '0') { $type->[$i] = 0 }
  165 100 100     286  
      100        
43 561         853 elsif ($dtype eq 'linear' or $dtype eq '1') { $type->[$i] = 1 }
44 2         11 else { return }
45             }
46 3         14 } else { return }
47              
48 274         1342 bless { basis => $basis, range => $range, type => $type }
49             }
50              
51 4398     4398 0 8807 sub basis { $_[0]{'basis'}}
52             sub dimension_is_int {
53 3123     3123 0 4488 my ($self, $dnr, $range) = @_;
54 3123   33     4931 $range //= $self->{'range'};
55 3123 50 33     8865 return undef unless ref $range eq 'ARRAY' and exists $range->[$dnr];
56 3123         3957 my $r = $range->[$dnr];
57 3123 100 100     8528 return 0 if $r->[0] == 0 and $r->[1] == 1; #normal
58 2448 100       3919 return 0 if int($r->[0]) != $r->[0];
59 2440 50       3764 return 0 if int($r->[1]) != $r->[1];
60 2440         6381 1;
61             }
62             sub _range {
63 1399     1399   2079 my ($self, $external_range) = @_;
64 1399 100       3217 return $self->{'range'} unless defined $external_range;
65              
66             # check if range def is valid and eval (exapand) it
67 209         467 $external_range = Graphics::Toolkit::Color::Space::Shape->new( $self->{'basis'}, $external_range, $self->{'type'});
68 209 100       725 return (ref $external_range) ? $external_range->{'range'} : undef ;
69             }
70              
71             ########################################################################
72              
73             sub delta { # values have to be normalized
74 110     110 0 6002 my ($self, $values1, $values2) = @_;
75 110 100 100     188 return unless $self->basis->is_array( $values1 ) and $self->basis->is_array( $values2 );
76 104         307 my @delta = map {$values2->[$_] - $values1->[$_] } $self->basis->iterator;
  314         589  
77 104 100       187 map { $self->{'type'}[$_] ? $delta[$_] :
  314 100       852  
    100          
78             $delta[$_] < -0.5 ? ($delta[$_]+1) :
79             $delta[$_] > 0.5 ? ($delta[$_]-1) : $delta[$_] } $self->basis->iterator;
80             }
81              
82             sub check {
83 259     259 0 2814 my ($self, $values, $range) = @_;
84 259 100       447 return carp 'color value vector in '.$self->basis->name.' needs '.$self->basis->count.' values'
85             unless $self->basis->is_array( $values );
86 238         506 $range = $self->_range( $range );
87 238 50       521 return carp "bad range definition" unless ref $range;
88 238         407 my @names = $self->basis->keys;
89 238         455 for my $i ($self->basis->iterator){
90 645 100       1460 return carp $names[$i]." value is below minimum of ".$range->[$i][0] if $values->[$i] < $range->[$i][0];
91 615 100       1301 return carp $names[$i]." value is above maximum of ".$range->[$i][1] if $values->[$i] > $range->[$i][1];
92 585 100 100     885 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 162         563 return;
96             }
97              
98             sub clamp {
99 249     249 0 8739 my ($self, $values, $range) = @_;
100 249         479 $range = $self->_range( $range );
101 249 100       584 return undef, carp "bad range definition, need upper limit, 2 element ARRAY or ARRAY of 2 element ARRAYs" unless ref $range;
102 248 50       482 $values = [] unless ref $values eq 'ARRAY';
103 248         598 push @$values, 0 while @$values < $self->basis->count;
104 248         518 pop @$values while @$values > $self->basis->count;
105 248         459 for my $i ($self->basis->iterator){
106 749         1217 my $delta = $range->[$i][1] - $range->[$i][0];
107 749 100       1302 if ($self->{'type'}[$i]){
108 629 100       1171 $values->[$i] = $range->[$i][0] if $values->[$i] < $range->[$i][0];
109 629 100       1105 $values->[$i] = $range->[$i][1] if $values->[$i] > $range->[$i][1];
110             } else {
111 120         283 $values->[$i] += $delta while $values->[$i] < $range->[$i][0];
112 120         276 $values->[$i] -= $delta while $values->[$i] > $range->[$i][1];
113 120 100       245 $values->[$i] = $range->[$i][0] if $values->[$i] == $range->[$i][1];
114             }
115 749 100       1145 $values->[$i] = round($values->[$i]) if $self->dimension_is_int($i, $range);
116             }
117 248         992 return @$values;
118             }
119              
120             ########################################################################
121              
122             sub normalize {
123 226     226 0 4562 my ($self, $values, $range) = @_;
124 226 50       358 return unless $self->basis->is_array( $values );
125 226         430 $range = $self->_range( $range );
126 226 50       443 return carp "bad range definition" unless ref $range;
127 226         366 map { ($values->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  679         1818  
128             }
129              
130             sub denormalize {
131 596     596 0 7364 my ($self, $values, $range) = @_;
132 596 50       1004 return unless $self->basis->is_array( $values );
133 596         1216 $range = $self->_range( $range );
134 596 100       1199 return carp "bad range definition" unless ref $range;
135 595         1031 my @val = map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0] } $self->basis->iterator;
  1789         4337  
136 595 100       1188 @val = map { $self->dimension_is_int($_, $range) ? round ($val[$_]) : $val[$_] } $self->basis->iterator;
  1789         2844  
137 595         1951 return @val;
138             }
139              
140             sub denormalize_range {
141 90     90 0 151 my ($self, $values, $range) = @_;
142 90 50       189 return unless $self->basis->is_array( $values );
143 90         183 $range = $self->_range( $range );
144 90 50       198 return carp "bad range definition" unless ref $range;
145 90         152 map { $values->[$_] * ($range->[$_][1]-$range->[$_][0]) } $self->basis->iterator;
  271         646  
146             }
147              
148             1;