File Coverage

lib/Graphics/Toolkit/Color/Values.pm
Criterion Covered Total %
statement 83 83 100.0
branch 24 32 75.0
condition 12 18 66.6
subroutine 11 11 100.0
pod 6 7 85.7
total 136 151 90.0


line stmt bran cond sub pod time code
1 6     6   709 use v5.12;
  6         19  
2 6     6   28 use warnings;
  6         11  
  6         280  
3              
4             # value objects with cache of original values
5              
6             package Graphics::Toolkit::Color::Values;
7 6     6   2989 use Graphics::Toolkit::Color::Space::Hub;
  6         21  
  6         215  
8 6     6   37 use Carp;
  6         12  
  6         7608  
9              
10             sub new {
11 226     226 1 5266 my ($pkg, $color_val) = @_;
12 226         450 my ($values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat( $color_val );
13 226 100       627 return carp "could not recognize color values" unless ref $values;
14 216         379 my $space = Graphics::Toolkit::Color::Space::Hub::get_space( $space_name );
15 216         405 my $std_space = Graphics::Toolkit::Color::Space::Hub::base_space();
16 216         333 my $self = {};
17 216         409 $self->{'origin'} = $space->name;
18 216         475 $values = [$space->clamp( $values )];
19 216         526 $values = [$space->normalize( $values )];
20 216         512 $self->{$space->name} = $values;
21 216 100       757 $self->{$std_space->name} = [$space->convert($values, $std_space->name)] if $space ne $std_space;
22 216         789 bless $self;
23             }
24              
25             sub get { # get a value tuple in any color space, range and format
26 579     579 1 2758 my ($self, $space_name, $format_name, $range_def) = @_;
27 579 50       1128 Graphics::Toolkit::Color::Space::Hub::check_space_name( $space_name ) and return;
28 579         927 my $std_space_name = $Graphics::Toolkit::Color::Space::Hub::base_package;
29 579   66     1248 $space_name //= $std_space_name;
30 579         992 my $space = Graphics::Toolkit::Color::Space::Hub::get_space( $space_name );
31             my $values = (exists $self->{$space->name})
32             ? $self->{$space->name}
33 579 100       1454 : [$space->deconvert( $self->{$std_space_name}, $std_space_name)];
34 579         1538 $values = [ $space->denormalize( $values, $range_def) ];
35 579         1268 Graphics::Toolkit::Color::Space::Hub::format( $values, $space_name, $format_name);
36             }
37 36     36 0 113 sub string { $_[0]->get( $_[0]->{'origin'}, 'string' ) }
38              
39             ########################################################################
40              
41             sub set { # %val --> _
42 8     8 1 16 my ($self, $val_hash) = @_;
43 8         21 my ($pos_hash, $space_name) = Graphics::Toolkit::Color::Space::Hub::partial_hash_deformat( $val_hash );
44 8 100       40 return carp 'key names: '.join(', ', keys %$val_hash). ' do not correlate to any supported color space' unless defined $space_name;
45 7         16 my @values = $self->get( $space_name );
46 7         23 for my $pos (keys %$pos_hash){
47 7         17 $values[$pos] = $pos_hash->{ $pos };
48             }
49 7         32 __PACKAGE__->new([$space_name, @values]);
50             }
51              
52             sub add { # %val --> _
53 7     7 1 14 my ($self, $val_hash) = @_;
54 7         19 my ($pos_hash, $space_name) = Graphics::Toolkit::Color::Space::Hub::partial_hash_deformat( $val_hash );
55 7 100       47 return carp 'key names: '.join(', ', keys %$val_hash). ' do not correlate to any supported color space' unless defined $space_name;
56 5         14 my @values = $self->get( $space_name );
57 5         17 for my $pos (keys %$pos_hash){
58 5         14 $values[$pos] += $pos_hash->{ $pos };
59             }
60 5         23 __PACKAGE__->new([$space_name, @values]);
61             }
62              
63             sub blend { # _c1 _c2 -- +factor ~space --> _
64 16     16 1 38 my ($self, $c2, $factor, $space_name ) = @_;
65 16 50       48 return carp "need value object as second argument" unless ref $c2 eq __PACKAGE__;
66 16   100     33 $factor //= 0.5;
67 16   100     32 $space_name //= 'HSL';
68 16 50       32 Graphics::Toolkit::Color::Space::Hub::check_space_name( $space_name ) and return;
69 16         36 my @values1 = $self->get( $space_name );
70 16         34 my @values2 = $c2->get( $space_name );
71 16         39 my @rvalues = map { ((1-$factor) * $values1[$_]) + ($factor * $values2[$_]) } 0 .. $#values1;
  49         107  
72 16         52 __PACKAGE__->new([$space_name, @rvalues]);
73             }
74              
75             ########################################################################
76              
77             sub distance { # _c1 _c2 -- ~space ~metric @range --> +
78 92     92 1 1510 my ($self, $c2, $space_name, $metric, $range) = @_;
79             #say "distance ";
80 92 100       217 return carp "need value object as second argument" unless ref $c2 eq __PACKAGE__;
81 90   100     203 $space_name //= 'HSL';
82 90 50       180 Graphics::Toolkit::Color::Space::Hub::check_space_name( $space_name ) and return;
83 90         166 my $space = Graphics::Toolkit::Color::Space::Hub::get_space( $space_name );
84 90 100       185 $metric = $space->basis->key_shortcut($metric) if $space->basis->is_key( $metric );
85 90         191 my @values1 = $self->get( $space_name, 'list', 'normal' );
86 90         196 my @values2 = $c2->get( $space_name, 'list', 'normal' );
87             #say "values: @values1 @values2 $space_name";
88 90 50 33     288 return unless defined $values1[0] and defined $values2[0];
89 90         218 my @delta = $space->delta( \@values1, \@values2 );
90             #say "normalized: @delta $metric" if defined $metric;
91              
92 90         207 @delta = $space->denormalize_range( \@delta, $range);
93             #say "denormal : @delta " if defined $metric;
94 90 50 33     298 return unless defined $delta[0] and @delta == $space->dimensions;
95              
96             # grep values for individual metric / subspace distance
97 90 100 66     264 if (defined $metric and $metric){
98 61         197 my @components = split( '', $metric );
99 61         118 my $pos = $space->basis->key_pos( $metric );
100             @components = defined( $pos )
101             ? ($pos)
102 86         149 : (map { $space->basis->shortcut_pos($_) }
103 61 50       130 grep { defined $space->basis->shortcut_pos($_) } @components);
  86         157  
104 61 50       127 return - carp "called 'distance' for metric $metric that does not fit color space $space_name!" unless @components;
105 61         88 @delta = map { $delta [$_] } @components;
  86         181  
106             }
107              
108             # Euclidean distance:
109 90         130 @delta = map {$_ * $_} @delta;
  174         273  
110 90         130 my $d = 0;
111 90         151 for (@delta) {$d += $_}
  174         253  
112 90         914 return sqrt $d;
113             }
114              
115             1;
116              
117             __END__