File Coverage

lib/Graphics/Toolkit/Color.pm
Criterion Covered Total %
statement 194 220 88.1
branch 124 144 86.1
condition 60 87 68.9
subroutine 21 42 50.0
pod 13 34 38.2
total 412 527 78.1


line stmt bran cond sub pod time code
1              
2             # public user level API: docs, help and arg cleaning
3              
4             package Graphics::Toolkit::Color;
5             our $VERSION = '1.98';
6              
7 4     4   565779 use v5.12;
  4         12  
8 4     4   21 use warnings;
  4         7  
  4         362  
9 4     4   24 use Exporter 'import';
  4         8  
  4         182  
10 4     4   1002 use Graphics::Toolkit::Color::Space::Util qw/is_nr/;
  4         11  
  4         297  
11 4     4   2039 use Graphics::Toolkit::Color::SetCalculator;
  4         17  
  4         22202  
12              
13             my $default_space_name = Graphics::Toolkit::Color::Space::Hub::default_space_name();
14             our @EXPORT_OK = qw/color/;
15              
16             ## constructor #########################################################
17              
18 23     23 1 736427 sub color { Graphics::Toolkit::Color->new ( @_ ) }
19              
20             sub new {
21 86     86 1 2404 my ($pkg, @args) = @_;
22 86         282 my $help = <
23             constructor new of Graphics::Toolkit::Color object needs either:
24             1. a color name: new('red') or new('SVG:red')
25             3. RGB hex string new('#FF0000') or new('#f00')
26             4. $default_space_name array or ARRAY ref: new( 255, 0, 0 ) or new( [255, 0, 0] )
27             5. named array or ARRAY ref: new( 'HSL', 255, 0, 0 ) or new( ['HSL', 255, 0, 0 ])
28             6. named string: new( 'HSL: 0, 100, 50' ) or new( 'ncol(r0, 0%, 0%)' )
29             7. HASH or HASH ref with values from RGB or any other space:
30             new(r => 255, g => 0, b => 0) or new({ hue => 0, saturation => 100, lightness => 50 })
31             EOH
32 86         383 my $first_arg_is_color_space = Graphics::Toolkit::Color::Space::Hub::is_space_name( $args[0] );
33 86 100 100     385 @args = ([ $args[0], @{$args[1]} ]) if @args == 2 and $first_arg_is_color_space and ref $args[1] eq 'ARRAY';
  2   66     9  
34 86 100 100     543 @args = ([ @args ]) if @args == 3 or (@args > 3 and $first_arg_is_color_space);
      100        
35 86 100 100     536 @args = ({ @args }) if @args == 6 or @args == 8;
36 86 100       311 return $help unless @args == 1;
37 77         286 my $self = _new_from_scalar_def( $args[0] );
38 77 100       830 return (ref $self) ? $self : $help;
39             }
40             sub _new_from_scalar_def { # color defs of method arguments
41 136     136   297 my ($color_def) = shift;
42 136 100       431 return $color_def if ref $color_def eq __PACKAGE__;
43 116         641 return _new_from_value_obj( Graphics::Toolkit::Color::Values->new_from_any_input( $color_def ) );
44             }
45             sub _new_from_value_obj {
46 285     285   652 my ($value_obj) = @_;
47 285 100       950 return $value_obj unless ref $value_obj eq 'Graphics::Toolkit::Color::Values';
48 237         1618 return bless {values => $value_obj};
49             }
50              
51              
52             ## deprecated methods - deleted with 2.0
53 0 0   0 0 0 sub string { $_[0]{'name'} || $_[0]->{'values'}->string }
54 0     0 0 0 sub rgb { $_[0]->values( ) }
55 0     0 0 0 sub red {($_[0]->values( ))[0] }
56 0     0 0 0 sub green {($_[0]->values( ))[1] }
57 0     0 0 0 sub blue {($_[0]->values( ))[2] }
58 0     0 0 0 sub rgb_hex { $_[0]->values( as => 'hex') }
59 0     0 0 0 sub rgb_hash { $_[0]->values( as => 'hash') }
60 0     0 0 0 sub hsl { $_[0]->values( in => 'hsl') }
61 0     0 0 0 sub hue {($_[0]->values( in => 'hsl'))[0] }
62 0     0 0 0 sub set { shift->set_value( @_ ) }
63 0     0 0 0 sub add { shift->add_value( @_ ) }
64 0     0 0 0 sub saturation {($_[0]->values( in => 'hsl'))[1] }
65 0     0 0 0 sub lightness {($_[0]->values( in => 'hsl'))[2] }
66 0     0 0 0 sub hsl_hash { $_[0]->values( in => 'hsl', as => 'hash') }
67 0     0 0 0 sub distance_to { distance(@_) }
68 0     0 0 0 sub blend { mix( @_ ) }
69 0     0 0 0 sub blend_with { $_[0]->mix( with => $_[1], amount => $_[2], in => 'HSL') }
70 0     0 0 0 sub gradient_to { hsl_gradient_to( @_ ) }
71 0     0 0 0 sub rgb_gradient_to { $_[0]->gradient( to => $_[1], steps => $_[2], dynamic => $_[3], in => 'RGB' ) }
72 0     0 0 0 sub hsl_gradient_to { $_[0]->gradient( to => $_[1], steps => $_[2], dynamic => $_[3], in => 'HSL' ) }
73 0     0 0 0 sub complementary { complement(@_) }
74              
75             sub _split_named_args {
76 160     160   586 my ($raw_args, $only_parameter, $required_parameter, $optional_parameter, $parameter_alias) = @_;
77 160 50 66     780 @$raw_args = %{$raw_args->[0]} if @$raw_args == 1 and ref $raw_args->[0] eq 'HASH' and not
  0   0     0  
      33        
78             (defined $only_parameter and $only_parameter eq 'to' and ref _new_from_scalar_def( $raw_args ) );
79              
80 160 100 100     605 if (@$raw_args == 1 and defined $only_parameter and $only_parameter){
      66        
81 34 50       94 return "The one default argument can not cover multiple, required parameter !" if @$required_parameter > 1;
82 34 50 66     124 return "The default argument does not cover the required argument!"
83             if @$required_parameter and $required_parameter->[0] ne $only_parameter;
84              
85 34         153 my %defaults = %$optional_parameter;
86 34         93 delete $defaults{$only_parameter};
87 34         217 return {$only_parameter => $raw_args->[0], %defaults};
88             }
89 126         212 my %clean_arg;
90 126 100       365 if (@$raw_args % 2) {
91 2 50 33     13 return (defined $only_parameter and $only_parameter)
92             ? "Got odd number of values, please use key value pairs as arguments or one default argument !\n"
93             : "Got odd number of values, please use key value pairs as arguments !\n"
94             }
95 124         412 my %arg_hash = @$raw_args;
96 124         305 for my $parameter_name (@$required_parameter){
97 68 100 66     400 if (ref $parameter_alias eq 'HASH' and exists $parameter_alias->{ $parameter_name }
      66        
98             and exists $arg_hash{ $parameter_alias->{$parameter_name} }){
99 10         34 $arg_hash{ $parameter_name } = delete $arg_hash{ $parameter_alias->{$parameter_name} };
100             }
101 68 100       283 return "Argument '$parameter_name' is missing\n" unless exists $arg_hash{$parameter_name};
102 62         223 $clean_arg{ $parameter_name } = delete $arg_hash{ $parameter_name };
103             }
104 118         389 for my $parameter_name (keys %$optional_parameter){
105 384 50 66     831 if (ref $parameter_alias eq 'HASH' and exists $parameter_alias->{ $parameter_name }
      33        
106             and exists $arg_hash{ $parameter_alias->{$parameter_name} }){
107 0         0 $arg_hash{ $parameter_name } = delete $arg_hash{ $parameter_alias->{$parameter_name} };
108             }
109             $clean_arg{ $parameter_name } = exists $arg_hash{$parameter_name}
110             ? delete $arg_hash{ $parameter_name }
111 384 100       1185 : $optional_parameter->{ $parameter_name };
112             }
113 118 100       400 return "Inserted unknown argument(s): ".(join ',', keys %arg_hash)."\n" if %arg_hash;
114 111         365 return \%clean_arg;
115             }
116              
117             ## getter ##############################################################
118             sub values {
119 57     57 1 54085 my ($self, @args) = @_;
120 57         523 my $arg = _split_named_args( \@args, 'in', [],
121             { in => $default_space_name, as => 'list',
122             precision => undef, range => undef, suffix => undef } );
123 57         265 my $help = <
124             GTC method 'values' accepts either no arguments, one color space name or four optional, named args:
125             values ( ...
126             in => 'HSL', # color space name, defaults to "$default_space_name"
127             as => 'css_string', # output format name, default is "list"
128             range => 1, # value range (SCALAR or ARRAY), default set by space def
129             precision => 3, # value precision (SCALAR or ARRAY), default set by space
130             suffix => '%', # value suffix (SCALAR or ARRAY), default set by color space
131              
132             EOH
133 57 100       191 return $arg.$help unless ref $arg;
134 56         431 $self->{'values'}->formatted( @$arg{qw/in as suffix range precision/} );
135             }
136              
137             sub name {
138 34     34 1 9898 my ($self, @args) = @_;
139 34 100       216 return $self->{'values'}->name unless @args;
140 2         18 my $arg = _split_named_args( \@args, 'from', [], {from => 'default', all => 0, full => 0, distance => 0});
141 2         8 my $help = <
142             GTC method 'name' accepts three optional, named arguments:
143             name ( ...
144             'CSS' # color naming scheme works as only positional argument
145             from => 'CSS' # same scheme (defaults to internal: X + CSS + PantoneReport)
146             from => ['SVG', 'X'] # more color naming schemes at once, without duplicates
147             all => 1 # returns list of all names with the object's RGB values (defaults 0)
148             full => 1 # adds color scheme name to the color name. 'SVG:red' (defaults 0)
149             distance => 3 # color names from within distance of 3 (defaults 0)
150             EOH
151 2         10 return Graphics::Toolkit::Color::Name::from_values( $self->{'values'}->shaped, @$arg{qw/from all full distance/});
152             }
153              
154             sub closest_name {
155 11     11 1 11778 my ($self, @args) = @_;
156 11         90 my $arg = _split_named_args( \@args, 'from', [], {from => 'default', all => 0, full => 0});
157 11         37 my $help = <
158             GTC method 'name' accepts three optional, named arguments:
159             closest_name ( ...
160             'CSS' # color naming scheme works as only positional argument
161             from => 'CSS' # same scheme (defaults to internal: X + CSS + PantoneReport)
162             from => ['SVG', 'X'] # more color naming schemes at once, without duplicates
163             all => 1 # returns list of all names with the object's RGB values (defaults 0)
164             full => 1 # adds color scheme name to the color name. 'SVG:red' (defaults 0)
165             EOH
166             my ($name, $distance) = Graphics::Toolkit::Color::Name::closest_from_values(
167 11         52 $self->{'values'}->shaped, @$arg{qw/from all full/});
168 11 100       88 return wantarray ? ($name, $distance) : $name;
169             }
170              
171             sub distance {
172 9     9 1 2033 my ($self, @args) = @_;
173 9         66 my $arg = _split_named_args( \@args, 'to', ['to'], {in => $default_space_name, select => undef, range => undef});
174 9         43 my $help = <
175             GTC method 'distance' accepts as arguments either a scalar color definition or
176             four named arguments, only the first being required:
177             distance ( ...
178             to => 'green' # color object or color definition (required)
179             in => 'HSL' # color space name, defaults to "$default_space_name"
180             select => 'red' # axis name or names (ARRAY ref), default is none
181             range => 2**16 # value range definition, defaults come from color space def
182             EOH
183 9 100       38 return $arg.$help unless ref $arg;
184 7         24 my $target_color = _new_from_scalar_def( $arg->{'to'} );
185 7 50       17 return "target color definition: $arg->{to} is ill formed" unless ref $target_color;
186 7         27 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} );
187 7 50       17 return "$color_space\n".$help unless ref $color_space;
188 7 100       21 if (defined $arg->{'select'}){
189 3 100       16 if (not ref $arg->{'select'}){
    50          
190             return $arg->{'select'}." is not an axis name in color space: ".$color_space->name
191 2 50       12 unless $color_space->is_axis_name( $arg->{'select'} );
192             } elsif (ref $arg->{'select'} eq 'ARRAY'){
193 1         3 for my $axis_name (@{$arg->{'select'}}) {
  1         4  
194 2 50       8 return "$axis_name is not an axis name in color space: ".$color_space->name
195             unless $color_space->is_axis_name( $axis_name );
196             }
197 0         0 } else { return "The 'select' argument needs one axis name or an ARRAY with several axis names".
198             " from the same color space!" }
199             }
200 7         24 my $range_def = $color_space->shape->try_check_range_definition( $arg->{'range'} );
201 7 50       19 return $range_def unless ref $range_def;
202             Graphics::Toolkit::Color::Space::Hub::distance(
203 7         30 $self->{'values'}->normalized, $target_color->{'values'}->normalized, $color_space->name ,$arg->{'select'}, $range_def );
204             }
205              
206             ## single color creation methods #######################################
207             sub set_value {
208 10     10 1 11036 my ($self, @args) = @_;
209 10 50 33     37 @args = %{$args[0]} if @args == 1 and ref $args[0] eq 'HASH';
  0         0  
210 10         22 my $help = <
211             GTC method 'set_value' needs a value HASH (not a ref) whose keys are axis names or
212             short names from one color space. If the chosen axis name(s) is/are ambiguous,
213             you might add the "in" argument:
214             set_value( green => 20 ) or set( g => 20 ) or
215             set_value( hue => 240, in => 'HWB' )
216             EOH
217 10 100 66     73 return $help if @args % 2 or not @args or @args > 10;
      66        
218 9         33 my $partial_color = { @args };
219 9         17 my $space_name = delete $partial_color->{'in'};
220 9         30 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name );
221 9 50       22 return "$color_space\n".$help unless ref $color_space;
222 9         42 _new_from_value_obj( $self->{'values'}->set( $partial_color, $space_name ) );
223             }
224              
225             sub add_value {
226 10     10 1 11732 my ($self, @args) = @_;
227 10 50 33     38 @args = %{$args[0]} if @args == 1 and ref $args[0] eq 'HASH';
  0         0  
228 10         24 my $help = <
229             GTC method 'add_value' needs a value HASH (not a ref) whose keys are axis names or
230             short names from one color space. If the chosen axis name(s) is/are ambiguous,
231             you might add the "in" argument:
232             add_value( blue => -10 ) or set( b => -10 )
233             add_value( hue => 100 , in => 'HWB' )
234             EOH
235 10 100 66     81 return $help if @args % 2 or not @args or @args > 10;
      66        
236 9         33 my $partial_color = { @args };
237 9         21 my $space_name = delete $partial_color->{'in'};
238 9         31 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name );
239 9 50       23 return "$color_space\n".$help unless ref $color_space;
240 9         44 _new_from_value_obj( $self->{'values'}->add( $partial_color, $space_name ) );
241             }
242              
243             sub mix {
244 24     24 1 25462 my ($self, @args) = @_;
245 24         159 my $arg = _split_named_args( \@args, 'to', ['to'], {in => $default_space_name, amount => -1});
246 24         145 my $help = <
247             GTC method 'mix' accepts three named arguments, only the first being required:
248             mix ( ...
249             to => ['HSL', 240, 100, 50] # scalar color definition or ARRAY ref thereof
250             amount => 20 # percentage value or ARRAY ref thereof, default is 50
251             in => 'HSL' # color space name, defaults to "$default_space_name"
252             Please note that either both or none of the first two arguments has to be an ARRAY.
253             Both ARRAY have to have the same length. 'amount' refers to the color(s) picked with 'to'.
254             EOH
255 24 100       72 return $arg.$help unless ref $arg;
256 22         97 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( delete $arg->{'in'} );
257 22 100       77 return "$color_space\n".$help unless ref $color_space;
258 21         63 my $recipe = _new_from_scalar_def( $arg->{'to'} );
259 21 100       59 if (ref $recipe){
260 10 100       42 return "argument 'amount' has to be a sacalar value if only one color is mixed !\n".$help if ref $arg->{'amount'};
261 9 100       38 $arg->{'amount'} = 50 if $arg->{'amount'} < 0;
262 9 100       25 $arg->{'amount'} = 100 if $arg->{'amount'} > 100;
263 9         45 $recipe = [{color => $recipe->{'values'}, percent => $arg->{'amount'}}];
264 9 100       59 push @$recipe, {color => $self->{'values'}, percent => 100 - $arg->{'amount'} } if $arg->{'amount'} < 100;
265              
266             } else {
267 11 100       39 if (ref $arg->{'to'} ne 'ARRAY'){
268 2         23 return "target color definition (argument 'to'): '$arg->{to}' is ill formed. It has to be one color definition or an ARRAY of the.";
269             } else {
270             return "Argument 'amount' has to be an ARRAY of same length as argument 'to' (color definitions)!\n".$help
271 9 100 66     61 if ref $arg->{'to'} eq 'ARRAY' and ref $arg->{'amount'} eq 'ARRAY' and @{$arg->{'amount'}} != @{$arg->{'to'}};
  4   100     11  
  4         23  
272 8         17 my $color_count = 1 + @{$arg->{'to'}};
  8         20  
273 8 100       24 unless (ref $arg->{'amount'}){
274             $arg->{'amount'} = ($arg->{'amount'} < 0)
275             ? [(100/$color_count) x $color_count]
276 5 50       33 : [($arg->{'amount'}) x $color_count];
277             }
278 8         17 $recipe = [];
279 8         11 my $amount_sum = 0;
280 8         13 for my $color_nr (0 .. $#{$arg->{'to'}}){
  8         34  
281 14         37 my $color_def = $arg->{'to'}[$color_nr];
282 14         27 my $color = _new_from_scalar_def( $color_def );
283 14 50       54 return "target color nr. $color_nr definition: '$color_def' is ill formed" unless ref $color;
284 14         100 push @$recipe, { color => $color->{'values'}, percent => $arg->{'amount'}[$color_nr] };
285 14         55 $amount_sum += $arg->{'amount'}[$color_nr];
286             }
287 8 100       40 push @$recipe, {color => $self->{'values'}, percent => 100 - $amount_sum } if $amount_sum < 100;
288 8 100       24 if ($amount_sum > 100){
289 1         8 $_->{'percent'} = ($_->{'percent'} / $amount_sum * 100) for @$recipe;
290             }
291             }
292             }
293 17         118 _new_from_value_obj( $self->{'values'}->mix( $recipe, $color_space ) );
294             }
295              
296             sub invert {
297 13     13 1 53 my ($self, @args) = @_;
298 13         72 my $arg = _split_named_args( \@args, 'in', [], {in => $default_space_name});
299 13         73 my $help = <
300             GTC method 'invert' accepts one optional argument, which can be positional or named:
301             invert ( ...
302             in => 'HSL' # color space name, defaults to "$default_space_name"
303             EOH
304 13 100       37 return $arg.$help unless ref $arg;
305 12         41 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} );
306 12 100       47 return "$color_space\n".$help unless ref $color_space;
307 11         63 _new_from_value_obj( $self->{'values'}->invert( $color_space ) );
308             }
309              
310             ## color set creation methods ##########################################
311             sub complement {
312 12     12 1 1092 my ($self, @args) = @_;
313 12         87 my $arg = _split_named_args( \@args, 'steps', [], {steps => 1, tilt => 0, target => {}});
314 12         42 my $help = <
315             GTC method 'complement' is computed in HSL and has two named, optional arguments:
316             complement ( ...
317             steps => 20 # count of produced colors, default is 1
318             tilt => 10 # default is 0
319             target => {h => 10, s => 20, l => 3} # sub-keys are independent, default to 0
320             EOH
321 12 100       53 return $arg.$help unless ref $arg;
322 11 100       44 return "Optional argument 'steps' has to be a number !\n".$help unless is_nr($arg->{'steps'});
323 9 50       31 return "Optional argument 'steps' is zero, no complement colors will be computed !\n".$help unless $arg->{'steps'};
324 9 100       21 return "Optional argument 'tilt' has to be a number !\n".$help unless is_nr($arg->{'tilt'});
325 8 100       44 return "Optional argument 'target' has to be a HASH ref !\n".$help if ref $arg->{'target'} ne 'HASH';
326 7         14 my ($target_values, $space_name);
327 7 100       11 if (keys %{$arg->{'target'}}){
  7         27  
328 2         16 ($target_values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat_partial_hash( $arg->{'target'}, 'HSL' );
329 2 100       19 return "Optional argument 'target' got HASH keys that do not fit HSL space (use 'h','s','l') !\n".$help
330             unless ref $target_values;
331 5         12 } else { $target_values = [] }
332 13         32 map {_new_from_value_obj( $_ )}
333 6         45 Graphics::Toolkit::Color::SetCalculator::complement( $self->{'values'}, @$arg{qw/steps tilt/}, $target_values );
334             }
335              
336             sub gradient {
337 14     14 1 2649 my ($self, @args) = @_;
338 14         129 my $arg = _split_named_args( \@args, 'to', ['to'], {steps => 10, tilt => 0, in => $default_space_name});
339 14         64 my $help = <
340             GTC method 'gradient' accepts four named arguments, only the first is required:
341             gradient ( ...
342             to => 'blue' # scalar color definition or ARRAY ref thereof
343             steps => 20 # count of produced colors, defaults to 10
344             tilt => 1 # dynamics of color change, defaults to 0
345             in => 'HSL' # color space name, defaults to "$default_space_name"
346             EOH
347 14 100       66 return $arg.$help unless ref $arg;
348 12         43 my @colors = ($self->{'values'});
349 12         49 my $target_color = _new_from_scalar_def( $arg->{'to'} );
350 12 100       42 if (ref $target_color) {
351 9         33 push @colors, $target_color->{'values'} }
352             else {
353 3 100 66     37 return "Argument 'to' contains malformed color definition!\n".$help if ref $arg->{'to'} ne 'ARRAY' or not @{$arg->{'to'}};
  2         13  
354 2         5 for my $color_def (@{$arg->{'to'}}){
  2         7  
355 5         14 my $target_color = _new_from_scalar_def( $color_def );
356 5 100       43 return "Argument 'to' contains malformed color definition: $color_def !\n".$help unless ref $target_color;
357 4         22 push @colors, $target_color->{'values'};
358             }
359             }
360             return "Argument 'steps' has to be a number greater zero !\n".$help
361 10 100 66     44 unless is_nr($arg->{'steps'}) and $arg->{'steps'} > 0;
362 9         35 $arg->{'steps'} = int $arg->{'steps'};
363 9 100       28 return "Argument 'tilt' has to be a number !\n".$help unless is_nr($arg->{'tilt'});
364 8         36 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} );
365 8 100       44 return "$color_space\n".$help unless ref $color_space;
366 53         96 map {_new_from_value_obj( $_ )}
367 7         47 Graphics::Toolkit::Color::SetCalculator::gradient( \@colors, @$arg{qw/steps tilt/}, $color_space);
368             }
369              
370             sub cluster {
371 18     18 1 11231 my ($self, @args) = @_;
372 18         161 my $arg = _split_named_args( \@args, undef, ['radius', 'minimal_distance'], {in => $default_space_name},
373             {radius => 'r', minimal_distance => 'min_d'} );
374 18         91 my $help = <
375             GTC method 'cluster' accepts three named arguments, the first two being required:
376             cluster ( ...
377             radius => 3 # ball shaped cluster with cuboctahedral packing or
378             r => [10, 5, 3] # cuboid shaped cluster with cubical packing
379             minimal_distance => 0.5 # minimal distance between colors in cluster
380             min_d => 0.5 # short alias for minimal distance
381             in => 'HSL' # color space name, defaults to "$default_space_name"
382             EOH
383 18 100       104 return $arg.$help unless ref $arg;
384 12         49 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} );
385 12 100       45 return "$color_space\n".$help unless ref $color_space;
386             return "Argument 'radius' has to be a number or an ARRAY of numbers".$help
387 11 100 100     41 unless is_nr($arg->{'radius'}) or $color_space->is_number_tuple( $arg->{'radius'} );
388             return "Argument 'distance' has to be a number greater zero !\n".$help
389 8 100 100     35 unless is_nr($arg->{'minimal_distance'}) and $arg->{'minimal_distance'} > 0;
390             return "Ball shaped cluster works only in spaces with three dimensions !\n".$help
391 6 100 100     54 if $color_space->axis_count > 3 and not ref $arg->{'radius'};
392 57         101 map {_new_from_value_obj( $_ )}
393 5         42 Graphics::Toolkit::Color::SetCalculator::cluster( $self->{'values'}, @$arg{qw/radius minimal_distance/}, $color_space);
394             }
395              
396             1;
397              
398             __END__