line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Color::TupleEncode::Baran; |
2
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
69
|
use warnings FATAL=>"all"; |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
427
|
|
4
|
8
|
|
|
8
|
|
41
|
use strict; |
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
222
|
|
5
|
|
|
|
|
|
|
|
6
|
8
|
|
|
8
|
|
43
|
use Carp; |
|
8
|
|
|
|
|
15
|
|
|
8
|
|
|
|
|
557
|
|
7
|
8
|
|
|
8
|
|
47
|
use Graphics::ColorObject; |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
298
|
|
8
|
8
|
|
|
8
|
|
49
|
use Color::TupleEncode; |
|
8
|
|
|
|
|
12
|
|
|
8
|
|
|
|
|
379
|
|
9
|
8
|
|
|
8
|
|
6727
|
use Math::VecStat qw(min max); |
|
8
|
|
|
|
|
9495
|
|
|
8
|
|
|
|
|
588
|
|
10
|
8
|
|
|
8
|
|
46
|
use POSIX qw(fmod); |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
91
|
|
11
|
8
|
|
|
8
|
|
7278
|
use Readonly; |
|
8
|
|
|
|
|
25434
|
|
|
8
|
|
|
|
|
13181
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#use Smart::Comments; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Color::TupleEncode::Baran - a utility class for C that |
18
|
|
|
|
|
|
|
implements color encoding of a 3-tuple C<(x,y,z)> to a color |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 VERSION |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Version 0.11 |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=cut |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our $VERSION = '0.11'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 SYNOPSIS |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
This is a utility module used by L. This module |
31
|
|
|
|
|
|
|
provides the default color encoding scheme. Therefore, if you do not |
32
|
|
|
|
|
|
|
explicitly set the encoding method in a L object explicitly, it will be set to C |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
To change or set the encoding method, pass the C |
35
|
|
|
|
|
|
|
directly or as an option in C or set with C. |
36
|
|
|
|
|
|
|
C |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
%options = (-method=>"Color::TupleEncode::Baran"); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
$encoder = Color::TupleEncode(options=>\%options); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# using the direct setter |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
$encoder->set_method("Color::TupleEncode::Baran"); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# setting method as an option individually |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
$convert->set_options(-method=>"Color::TupleEncode::Baran"); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
This module is not designed to be used directly. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 ENCODING ALGORITHM |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
This module encodes a 3-tuple C<(x,y,z)> to a HSV color using the scheme described in |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
Visualization of three-way comparisons of omics data |
57
|
|
|
|
|
|
|
Richard Baran Martin Robert, Makoto Suematsu, Tomoyoshi Soga1 and Masaru Tomita |
58
|
|
|
|
|
|
|
BMC Bioinformatics 2007, 8:72 doi:10.1186/1471-2105-8-72 |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
This publication can be accessed at L |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
This class encodes a 3-tuple C<(x,y,z)> (or C<(a,b,c)> in accordance with the terminology in the publication) to a HSV color C<(h,s,v)>. The following parameters are supported |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# for hue default |
65
|
|
|
|
|
|
|
-ha 0 |
66
|
|
|
|
|
|
|
-hb 20 |
67
|
|
|
|
|
|
|
-hc 240 |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# for saturation - set using hash reference as |
70
|
|
|
|
|
|
|
# option value, e.g. -saturation=>{dmin=>0.2,dmax=>0.8} |
71
|
|
|
|
|
|
|
-saturation dmin 0 |
72
|
|
|
|
|
|
|
dmax 1 |
73
|
|
|
|
|
|
|
min 0 |
74
|
|
|
|
|
|
|
max 0 |
75
|
|
|
|
|
|
|
relative 0 |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# for value - set using has reference as |
78
|
|
|
|
|
|
|
# option value, e.g. -saturation=>{min=>0.2} |
79
|
|
|
|
|
|
|
-value dmin NOT SET |
80
|
|
|
|
|
|
|
dmax NOT SET |
81
|
|
|
|
|
|
|
min 0 |
82
|
|
|
|
|
|
|
max 1 |
83
|
|
|
|
|
|
|
relative 0 |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Options are set using |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
%options=>{-ha=>60, -hb=>180, -hc=>300, -saturation=>{dmin=>0,dmax=>2}} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
$encoder = Color::TupleEncode(method=>"Color::TupleEncode::2Way", |
90
|
|
|
|
|
|
|
options=>\%options); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
or |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
$encoder->set_options(-ha=>60); |
95
|
|
|
|
|
|
|
$encoder->set_options(-ha=>60, -saturation=>{dmin=>0,dmax=>2}); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
See C for a chart of encoded colors. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
The color components are calculated as follows. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head2 Hue |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Given the tuple C<(a,b,c)>, let the characteristic hues for each tuple be C. Form the differences |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
dab = | a - b | |
106
|
|
|
|
|
|
|
dac = | a - c | |
107
|
|
|
|
|
|
|
dbc = | b - c | |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
The hue is calculated along the gradient formed by the two components that form the largest difference. For example, if C is the largest difference, the final hue lies along the gradient formed by C<(ha,hc)>. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
hue = 0 if a = b = c |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# values of hue below are fractional in the range [0,1] and |
114
|
|
|
|
|
|
|
# always modulo 1 (e.g. hue=1.2 becomes 0.2). |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
hue = ha + ( hb - ha ) * dbc / dab if dab >= dbc and dab >= dac |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
hue = hb + ( hc - hb ) * dac / dbc if dbc > dab and dbc >= dac |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
hue = hc + ( ha + 1 - hc ) * dab / dac if dac > dab and dac > dbc |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# convert from [0,1] to [0,360] |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
hue = hue * 360 |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
The effect of this encoding is to emphasize the component that is the most different. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
If two components equal and the third is very different, e.g. C<(0.1,1,0.1)> then the encoded hue will the characteristic hue of the largest component. In this case C. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
When the difference in the close values is small C<(0.1,1,0.15)> the encoded hue will be very close to the characterstic hue of the most different component. In this case, the hue will be very close to C - the hue is C. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
When the values are spread equally C<(0.3,0.6,0.9)> the hue will be half way between the characteristic hues of the components that form the largest difference. In this case, the hue will lie between C and C - the hue is C. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 Saturation |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Given the tuple C<(a,b,c)> and the differences |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
dab = | a - b | |
139
|
|
|
|
|
|
|
dac = | a - c | |
140
|
|
|
|
|
|
|
dbc = | b - c | |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
let |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
d = max( dab, dac, dbc ) |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Saturation is given by |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
s = 0 if d <= dmin |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
s = 1 if d >= dmax |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
s = ( d - dmin ) / ( dmax - dmin ) if dmin < d < dmax |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Thus, saturation is interpolated when the maximum difference C is within C<[ dmin, dmax ]>. These limits are set by C. For example |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
$encoder->set_options( -saturation => { dmin => 0.25, dmax => 0.75 } ); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
would result in saturation varying from its minimum to maximum value from C to C. Depending on the magnitude of the difference in components in your tuples, you will want to adjust the difference range to match. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
If the C<-relative> option is used, then a relative correction is applied to C if C 0> before saturation is calculated. Note that with this correction, C will always be in the range C<[ 0, 1 ]>. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
drel = d / max( |a|, |b|, |c|, d ) |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
d <- drel |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Saturation can be constrained within a range C<[ min, max ]> by setting the C parameters. These values must be in the range [0,1]. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
$encoder->set_options( -saturation => { min => 0.25, max => 0.75 } ); |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
You can set C E C (e.g. saturation increases as C increases), or C E C (e.g. saturatio decreases as C increases). |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
If either of C<(dmin,dmax)> parameters are not set, C always. You can clear a parameter by setting it to C. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
$encoder->set_options( -saturation => { -dmin => undef, -dmax => undef } ) |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
To toggle the use of relative difference, |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
$encoder->set_options( -saturation => { relative => 1 } ); |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
The I publication in which this encoding was introduced suggests to use the product of absolute and relative saturations as the final saturation. This can be done by calculating two values of saturation, one with the C<-saturation=>{relative=>0}> option, and one with C<-saturation=>{relative=>1}>. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
You can combine saturation and value encoding together. See the L section. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head2 Value |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
The value is defined analogously to saturation. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
You can supplement saturation encoding with value encoding as follows. Set the difference range C<[ dmin, dmax ]> for value to be higher/lower than the difference range for saturation. For example, |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$encoder->set_options(-saturation => { dmin => 0 , dmax => 2}, |
191
|
|
|
|
|
|
|
-value => { dmin => 2 , dmax => 5 , min => 1 , max => 0 }; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
The effect will be to adjust saturation when the largest component difference is in the range C<[0,2]> (from C to C). Thus as the difference grows, the color becomes more saturated. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
In the range C<[ 2, 5 ]>, C since the range is beyond C set for saturation. However, in this higher range the value will be adjusted from C to C. Thus, as the difference grows, the color gets darker. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Below is an example of the HSV values for various C<( x, y, z)> using the options above. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
0 , 0.1 , 1.0 251 0.50 1.0 |
200
|
|
|
|
|
|
|
0 , 0.1 , 1.5 248 0.75 1.0 |
201
|
|
|
|
|
|
|
0 , 0.1 , 2.0 246 1.00 1.0 |
202
|
|
|
|
|
|
|
0 , 0.1 , 3.0 243 1.00 0.67 |
203
|
|
|
|
|
|
|
0 , 0.1 , 4.0 242 1.00 0.33 |
204
|
|
|
|
|
|
|
0 , 0.1 , 5.0 242 1.00 0.00 |
205
|
|
|
|
|
|
|
0 , 0.1 , 6.0 242 1.00 0.00 |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
You can obtain these values with C as follows, for each tuple, |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
> examples/example-3way -options "{-saturation=>{dmin=>0,dmax=>2}, |
210
|
|
|
|
|
|
|
-value=>{dmin=2,dmax=>5,min=>1,max=>0}}" |
211
|
|
|
|
|
|
|
-tuple 0,0.1,1.5 |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head1 EXPORT |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Exports nothing. |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Use L. The method implemented by this module is used by default. |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=cut |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=for comment |
223
|
|
|
|
|
|
|
Given a data triplet, return the corresponding value. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=cut |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Readonly::Scalar our $TUPLE_SIZE => 3; |
228
|
|
|
|
|
|
|
Readonly::Array our @OPTIONS_OK => (qw(-ha -hb -hc -saturation -value)); |
229
|
|
|
|
|
|
|
Readonly::Hash our %OPTIONS_DEFAULT => (-ha=>0,-hb=>120,-hc=>240,-saturation=>{dmin=>0,dmax=>1}); |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub _get_value { |
232
|
144
|
|
|
144
|
|
286
|
my $self = shift; |
233
|
144
|
|
|
|
|
455
|
my ($a,$b,$c) = $self->get_tuple; |
234
|
144
|
|
|
|
|
264
|
my ($dmin,$dmax); |
235
|
|
|
|
|
|
|
# These are the hard limits on value. |
236
|
144
|
|
|
|
|
226
|
my ($vmin,$vmax) = (1,0); |
237
|
|
|
|
|
|
|
# Value options can be one or more of |
238
|
|
|
|
|
|
|
# min, max, dmin, dmax, relative |
239
|
144
|
|
|
|
|
393
|
my $options = $self->get_options(qw(-value)); |
240
|
144
|
|
|
|
|
405
|
return _get_interpolated_component($a,$b,$c,$vmin,$vmax,$options,"value"); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=for comment |
245
|
|
|
|
|
|
|
Given a data triplet, return the corresponding saturation |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=cut |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub _get_saturation { |
250
|
144
|
|
|
144
|
|
259
|
my $self = shift; |
251
|
144
|
|
|
|
|
498
|
my ($a,$b,$c) = $self->get_tuple; |
252
|
144
|
|
|
|
|
240
|
my ($s,$dmin,$dmax); |
253
|
144
|
|
|
|
|
357
|
my ($smin,$smax) = (0,1); |
254
|
144
|
|
|
|
|
384
|
my $options = $self->get_options(qw(-saturation)); |
255
|
144
|
|
|
|
|
432
|
return _get_interpolated_component($a,$b,$c,$smin,$smax,$options,"saturation"); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=for comment |
259
|
|
|
|
|
|
|
Given a data triplet, return the corresponding hue. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=cut |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub _get_hue { |
264
|
144
|
|
|
144
|
|
255
|
my $self = shift; |
265
|
144
|
|
|
|
|
445
|
my ($a,$b,$c) = $self->get_tuple; |
266
|
144
|
|
|
|
|
460
|
my ($ha,$hb,$hc) = $self->get_options(qw(-ha -hb -hc)); |
267
|
144
|
50
|
|
|
|
418
|
$ha /= 360 if $ha > 1; |
268
|
144
|
50
|
|
|
|
384
|
$hb /= 360 if $hb > 1; |
269
|
144
|
50
|
|
|
|
418
|
$hc /= 360 if $hc > 1; |
270
|
144
|
|
|
|
|
173
|
my $h = 0; |
271
|
144
|
100
|
100
|
|
|
1496
|
if($a == $b && $a == $c) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
272
|
16
|
|
|
|
|
20
|
$h = 0; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
elsif (abs($a-$b) >= abs($b-$c) && abs($a-$b) >= abs($a-$c)) { |
275
|
76
|
|
|
|
|
240
|
$h = $ha + ($hb-$ha)*abs($b-$c)/abs($a-$b); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
elsif (abs($b-$c) > abs($a-$b) && abs($b-$c) >= abs($a-$c)) { |
278
|
24
|
|
|
|
|
68
|
$h = $hb + ($hc-$hb)*abs($a-$c)/abs($b-$c); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
elsif (abs($a-$c) > abs($a-$b) && abs($a-$c) > abs($b-$c)) { |
281
|
28
|
|
|
|
|
92
|
$h = $hc + ($ha-$hc+1)*abs($a-$b)/abs($a-$c); |
282
|
28
|
|
|
|
|
102
|
$h = fmod($h,1); |
283
|
|
|
|
|
|
|
} else { |
284
|
0
|
|
|
|
|
0
|
confess "couldn't find hue for $a,$b,$c"; |
285
|
|
|
|
|
|
|
} |
286
|
144
|
|
|
|
|
1308
|
return 360*$h; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=for comment |
290
|
|
|
|
|
|
|
Common function for saturation and value. Interpolates the |
291
|
|
|
|
|
|
|
tuple a,b,c between component_min and component_max. Options in $options control the process. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=cut |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub _get_interpolated_component { |
296
|
288
|
|
|
288
|
|
996
|
my ($a,$b,$c,$component_min,$component_max,$options,$component_name) = @_; |
297
|
|
|
|
|
|
|
# ranges on the component |
298
|
288
|
|
|
|
|
423
|
my ($min,$max) = ($component_min,$component_max); |
299
|
|
|
|
|
|
|
# ranges on the difference |
300
|
288
|
|
|
|
|
301
|
my ($dmin,$dmax); |
301
|
288
|
100
|
|
|
|
597
|
if(defined $options) { |
302
|
144
|
50
|
|
|
|
460
|
if(ref($options) eq "HASH") { |
303
|
144
|
50
|
|
|
|
437
|
$min = $options->{min} if defined $options->{min}; |
304
|
144
|
50
|
|
|
|
360
|
$max = $options->{max} if defined $options->{max}; |
305
|
144
|
50
|
|
|
|
407
|
$dmin = $options->{dmin} if defined $options->{dmin}; |
306
|
144
|
50
|
|
|
|
983
|
$dmax = $options->{dmax} if defined $options->{dmax}; |
307
|
|
|
|
|
|
|
} else { |
308
|
0
|
|
|
|
|
0
|
confess "-$component_name option for must be a hash reference, e.g. -$component_name=>{dmin=>0,dmax=>1}"; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
288
|
50
|
|
|
|
846
|
if($min < min($component_min,$component_max)) { |
312
|
0
|
|
|
|
|
0
|
confess "$component_name minimum must be ".min($component_min,$component_max); |
313
|
|
|
|
|
|
|
} |
314
|
288
|
50
|
|
|
|
6207
|
if($max > max($component_min,$component_max)) { |
315
|
0
|
|
|
|
|
0
|
confess "$component_name maximum must be ".max($component_min,$component_max); |
316
|
|
|
|
|
|
|
} |
317
|
288
|
|
|
|
|
5259
|
my $t; # this is the interpolation parameter 0..1 |
318
|
288
|
100
|
66
|
|
|
1124
|
if(! defined $dmin || ! defined $dmax) { |
319
|
144
|
|
|
|
|
190
|
$t = 0; |
320
|
|
|
|
|
|
|
} else { |
321
|
144
|
100
|
100
|
|
|
991
|
if($a == $b && $b == $c) { |
|
|
50
|
33
|
|
|
|
|
322
|
16
|
|
|
|
|
24
|
$t = 0; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
elsif(defined $dmin && defined $dmax) { |
325
|
128
|
|
|
|
|
346
|
my $d = _get_maxdiff($a,$b,$c); |
326
|
128
|
50
|
33
|
|
|
2643
|
if(defined $options && $options->{relative}) { |
327
|
0
|
|
|
|
|
0
|
my $rel_factor = max(abs($a),abs($b),abs($c),$d); |
328
|
0
|
0
|
|
|
|
0
|
if($rel_factor) { |
329
|
0
|
|
|
|
|
0
|
$d /= $rel_factor; |
330
|
|
|
|
|
|
|
} else { |
331
|
|
|
|
|
|
|
# this should never happen because a=b=c=0 test |
332
|
|
|
|
|
|
|
# has been done above |
333
|
0
|
|
|
|
|
0
|
$d = 0; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
128
|
50
|
|
|
|
390
|
if($d <= $dmin) { |
|
|
100
|
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
$t = 0; |
338
|
|
|
|
|
|
|
} elsif ($d >= $dmax) { |
339
|
36
|
|
|
|
|
78
|
$t = 1; |
340
|
|
|
|
|
|
|
} else { |
341
|
92
|
|
|
|
|
240
|
$t = ($d-$dmin)/($dmax-$dmin); |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
else { |
345
|
0
|
|
|
|
|
0
|
$t = 0; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
## $v |
349
|
|
|
|
|
|
|
## $vmin |
350
|
|
|
|
|
|
|
## $vmax |
351
|
288
|
|
|
|
|
849
|
my $component = _interpolate($t,$min,$max); |
352
|
288
|
|
|
|
|
2730
|
return $component; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=for comment |
356
|
|
|
|
|
|
|
Interpolate value (0..1) between max and min |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=cut |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub _interpolate { |
361
|
288
|
|
|
288
|
|
419
|
my ($x,$min,$max) = @_; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
#my $min_real = $min < $max ? $min : $max; |
364
|
|
|
|
|
|
|
#my $max_real = $max > $min ? $max : $min; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
## $x |
367
|
|
|
|
|
|
|
## $min |
368
|
|
|
|
|
|
|
## $max |
369
|
|
|
|
|
|
|
|
370
|
288
|
100
|
|
|
|
719
|
if($x <= 0) { |
|
|
100
|
|
|
|
|
|
371
|
160
|
|
|
|
|
321
|
return $min; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
elsif ($x >= 1) { |
374
|
36
|
|
|
|
|
74
|
return $max; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
else { |
377
|
92
|
|
|
|
|
211
|
my $d = $max - $min; |
378
|
92
|
|
|
|
|
115
|
$d = $d * $x; |
379
|
92
|
|
|
|
|
132
|
$d = $min + $d; |
380
|
92
|
|
|
|
|
170
|
my $xi = $min + $x * ($max-$min); |
381
|
92
|
|
|
|
|
279
|
return $xi; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=for comment |
386
|
|
|
|
|
|
|
Retrieve largest difference |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=cut |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub _get_maxdiff { |
391
|
128
|
|
|
128
|
|
356
|
my ($a,$b,$c) = @_; |
392
|
128
|
|
|
|
|
797
|
return scalar max(abs($a-$b),abs($a-$c),abs($b-$c)); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=for comment |
396
|
|
|
|
|
|
|
Returns the tuple size for this encoding. |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=cut |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub _get_tuple_size { |
401
|
230
|
|
|
230
|
|
759
|
return $TUPLE_SIZE; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=for comment |
405
|
|
|
|
|
|
|
Returns a list of options that this implementation understands. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=cut |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub _get_ok_options { |
410
|
2606
|
|
|
2606
|
|
8473
|
return @OPTIONS_OK; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=for comment |
414
|
|
|
|
|
|
|
Returns a hash of default options for this implementation |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=cut |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub _get_default_options { |
419
|
256
|
|
|
256
|
|
1125
|
return %OPTIONS_DEFAULT; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=pod |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 IMPLEMENTING AN ENCODING CLASS |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
The encoding class must implement the following functions. Given a C object C<$obj>, |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head2 C<$value = _get_value( $obj )> |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=head2 C<$saturation = _get_saturation( $obj )> |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head2 C<$hue = _get_hue( $obj )> |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head2 C<$size = _get_tuple_size()> |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head2 C<@opt_ok =_get_ok_options()> |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head2 C<%opt_def = _get_default_options()> |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=head1 AUTHOR |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
Martin Krzywinski, C<< >> |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=head1 BUGS |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
447
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
448
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=head1 SUPPORT |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
perldoc Color::TupleEncode |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
You can also look for information at: |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=over 4 |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
L |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
L |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=item * CPAN Ratings |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
L |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=item * Search CPAN |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
L |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=back |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=head1 SEE ALSO |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
For details about the color encoding, see |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=over |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=item Color::TupleEncode |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
Driver module. This is the module that provides an API for the color encoding. See L. |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=item Color::TupleEncode::2Way |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
A utility module that encodes a 2-tuple to a color. See L. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=back |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Copyright 2010 Martin Krzywinski. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
499
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
500
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=cut |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
1; # End of Color::TupleEncode::Baran |