| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
# geometry of space: value range checks, normalisation and computing distance |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Graphics::Toolkit::Color::Space::Shape; |
|
5
|
34
|
|
|
34
|
|
378183
|
use v5.12; |
|
|
34
|
|
|
|
|
158
|
|
|
6
|
34
|
|
|
34
|
|
209
|
use warnings; |
|
|
34
|
|
|
|
|
75
|
|
|
|
34
|
|
|
|
|
1938
|
|
|
7
|
34
|
|
|
34
|
|
1221
|
use Graphics::Toolkit::Color::Space::Basis; |
|
|
34
|
|
|
|
|
161
|
|
|
|
34
|
|
|
|
|
1240
|
|
|
8
|
34
|
|
|
34
|
|
264
|
use Graphics::Toolkit::Color::Space::Util qw/round_decimals is_nr/; |
|
|
34
|
|
|
|
|
80
|
|
|
|
34
|
|
|
|
|
119411
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#### constructor ####################################################### |
|
11
|
|
|
|
|
|
|
sub new { |
|
12
|
325
|
|
|
325
|
0
|
16473
|
my $pkg = shift; |
|
13
|
325
|
|
|
|
|
1287
|
my ($basis, $type, $range, $precision, $constraint) = @_; |
|
14
|
325
|
100
|
|
|
|
1079
|
return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis'; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# expand axis type definition |
|
17
|
324
|
100
|
100
|
|
|
1241
|
if (not defined $type){ $type = [ (1) x $basis->axis_count ] } # set all axis as linear per default |
|
|
193
|
100
|
|
|
|
646
|
|
|
18
|
|
|
|
|
|
|
elsif (ref $type eq 'ARRAY' and @$type == $basis->axis_count ) { |
|
19
|
129
|
|
|
|
|
371
|
for my $i ($basis->axis_iterator) { |
|
20
|
385
|
|
|
|
|
635
|
my $atype = $type->[$i]; # type def of this axis |
|
21
|
385
|
50
|
|
|
|
725
|
return unless defined $atype; |
|
22
|
385
|
100
|
100
|
|
|
2018
|
if ($atype eq 'angular' or $atype eq 'circular' or $atype eq '0') { $type->[$i] = 0 } |
|
|
131
|
100
|
100
|
|
|
347
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
23
|
248
|
|
|
|
|
562
|
elsif ($atype eq 'linear' or $atype eq '1') { $type->[$i] = 1 } |
|
24
|
4
|
|
|
|
|
10
|
elsif ($atype eq 'no' or $atype eq '2') { $type->[$i] = 2 } |
|
25
|
2
|
|
|
|
|
21
|
else { return 'invalid axis type at element '.$i.'. It has to be "angular", "linear" or "no".' } |
|
26
|
|
|
|
|
|
|
} |
|
27
|
2
|
|
|
|
|
7
|
} else { return 'invalid axis type definition in color space '.$basis->space_name } |
|
28
|
|
|
|
|
|
|
|
|
29
|
320
|
|
|
|
|
958
|
$range = expand_range_definition( $basis, $range ); |
|
30
|
320
|
100
|
|
|
|
916
|
return $range unless ref $range; |
|
31
|
312
|
|
|
|
|
785
|
$precision = expand_precision_definition( $basis, $precision ); |
|
32
|
312
|
100
|
|
|
|
782
|
return $precision unless ref $precision; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# check constraint def |
|
35
|
310
|
100
|
|
|
|
707
|
if (defined $constraint){ |
|
36
|
9
|
100
|
100
|
|
|
59
|
return 'color space constraint definition has to be not empty a HASH ref' if ref $constraint ne 'HASH' or not %$constraint; |
|
37
|
7
|
|
|
|
|
24
|
for my $const_name (keys %$constraint){ |
|
38
|
8
|
|
|
|
|
17
|
my $const_properties = $constraint->{$const_name}; |
|
39
|
|
|
|
|
|
|
return 'color space constraint "$const_name" need the properties: "checker", "remedy" and error "remedy"' |
|
40
|
8
|
100
|
66
|
|
|
64
|
unless exists $const_properties->{'checker'} and exists $const_properties->{'remedy'} and exists $const_properties->{'error'}; |
|
|
|
|
100
|
|
|
|
|
|
41
|
6
|
100
|
|
|
|
24
|
return 'color space constraint "$const_name" property: "checker" has to be a CODE ref' unless ref $const_properties->{'checker'} eq 'CODE'; |
|
42
|
5
|
100
|
|
|
|
20
|
return 'color space constraint "$const_name" property: "remedy" has to be a CODE ref' unless ref $const_properties->{'remedy'} eq 'CODE'; |
|
43
|
4
|
100
|
|
|
|
18
|
return 'color space constraint "$const_name" property: "error" has to be a error message string' if ref $const_properties->{'error'}; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
301
|
|
|
|
|
593
|
} else { $constraint = {} } |
|
46
|
|
|
|
|
|
|
|
|
47
|
303
|
|
|
|
|
2142
|
bless { basis => $basis, type => $type, range => $range, precision => $precision, constraint => $constraint } |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
#### object attribute checker ########################################## |
|
51
|
|
|
|
|
|
|
sub expand_range_definition { # check if range def is valid and eval (expand) it |
|
52
|
1499
|
|
|
1499
|
0
|
2955
|
my ($basis, $range) = @_; |
|
53
|
1499
|
50
|
|
|
|
4210
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
54
|
1499
|
|
|
|
|
2505
|
my $error_msg = 'Bad value range definition!'; |
|
55
|
1499
|
100
|
100
|
|
|
6199
|
$range = 1 if not defined $range or $range eq 'normal'; |
|
56
|
1499
|
100
|
|
|
|
9100
|
$range = 100 if $range eq 'percent'; |
|
57
|
1499
|
100
|
66
|
|
|
7386
|
return $error_msg." It has to be 'normal', 'percent', a number or ARRAY of numbers or ARRAY of ARRAY's with two number!" |
|
|
|
|
100
|
|
|
|
|
|
58
|
|
|
|
|
|
|
unless (not ref $range and is_nr( $range )) or (ref $range eq 'ARRAY') ; |
|
59
|
1498
|
100
|
|
|
|
5246
|
$range = [$range] unless ref $range; |
|
60
|
1498
|
100
|
|
|
|
5669
|
$range = [(@$range) x $basis->axis_count] if @$range == 1; |
|
61
|
1498
|
100
|
|
|
|
4279
|
return "Range definition needs inside an ARRAY either one definition for all axis or one definition". |
|
62
|
|
|
|
|
|
|
" for each axis!" if @$range != $basis->axis_count; |
|
63
|
1495
|
|
|
|
|
3536
|
for my $axis_index ($basis->axis_iterator) { |
|
64
|
4516
|
|
|
|
|
7332
|
my $axis_range = $range->[$axis_index]; |
|
65
|
4516
|
100
|
|
|
|
8032
|
if (not ref $axis_range){ |
|
|
|
50
|
|
|
|
|
|
|
66
|
4254
|
100
|
|
|
|
9439
|
if ($axis_range eq 'normal') {$range->[$axis_index] = [0, 1]} |
|
|
3
|
50
|
|
|
|
11
|
|
|
67
|
0
|
|
|
|
|
0
|
elsif ($axis_range eq 'percent') {$range->[$axis_index] = [0, 100]} |
|
68
|
4251
|
|
|
|
|
11050
|
else {$range->[$axis_index] = [0, $axis_range+0]} |
|
69
|
|
|
|
|
|
|
} elsif (ref $axis_range eq 'ARRAY') { |
|
70
|
262
|
100
|
|
|
|
682
|
return $error_msg.' Array at axis number '.$axis_index.' has to have two elements' unless @$axis_range == 2; |
|
71
|
260
|
50
|
|
|
|
649
|
return $error_msg.' None numeric value at lower bound for axis number '.$axis_index unless is_nr( $axis_range->[0] ); |
|
72
|
260
|
100
|
|
|
|
674
|
return $error_msg.' None numeric value at upper bound for axis number '.$axis_index unless is_nr( $axis_range->[1] ); |
|
73
|
259
|
100
|
|
|
|
842
|
return $error_msg.' Lower bound (first value) is >= than upper bound at axis number '.$axis_index if $axis_range->[0] >= $axis_range->[1]; |
|
74
|
0
|
|
|
|
|
0
|
} else { return "Range definitin for axis $axis_index was not an two element ARRAY!" } |
|
75
|
|
|
|
|
|
|
} |
|
76
|
1491
|
|
|
|
|
4182
|
return $range; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
sub try_check_range_definition { # check if range def is valid and eval (expand) it |
|
79
|
3591
|
|
|
3591
|
0
|
7060
|
my ($self, $range) = @_; |
|
80
|
3591
|
100
|
|
|
|
10898
|
return $self->{'range'} unless defined $range; |
|
81
|
1179
|
|
|
|
|
2839
|
return expand_range_definition( $self->{'basis'}, $range ); |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub expand_precision_definition { # check if precision def is valid and eval (exapand) it |
|
85
|
321
|
|
|
321
|
0
|
648
|
my ($basis, $precision) = @_; |
|
86
|
321
|
50
|
|
|
|
919
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
87
|
321
|
100
|
|
|
|
770
|
$precision = -1 unless defined $precision; |
|
88
|
321
|
100
|
|
|
|
1234
|
$precision = [($precision) x $basis->axis_count] unless ref $precision; |
|
89
|
321
|
50
|
|
|
|
2451
|
return 'need an ARRAY as definition of axis value precision' unless ref $precision eq 'ARRAY'; |
|
90
|
321
|
100
|
|
|
|
3144
|
return 'definition of axis value precision has to have same lengths as basis' unless @$precision == $basis->axis_count; |
|
91
|
319
|
|
|
|
|
718
|
return $precision; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
sub try_check_precision_definition { # check if range def is valid and eval (expand) it |
|
94
|
999
|
|
|
999
|
0
|
2102
|
my ($self, $precision) = @_; |
|
95
|
999
|
100
|
|
|
|
3133
|
return $self->{'precision'} unless defined $precision; |
|
96
|
9
|
|
|
|
|
36
|
return expand_precision_definition( $self->{'basis'}, $precision ); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#### getter of space object ############################################ |
|
100
|
9996
|
|
|
9996
|
0
|
26825
|
sub basis { $_[0]{'basis'}} |
|
101
|
|
|
|
|
|
|
# per axis |
|
102
|
|
|
|
|
|
|
sub is_axis_numeric { |
|
103
|
13232
|
|
|
13232
|
0
|
23211
|
my ($self, $axis_nr) = @_; |
|
104
|
13232
|
100
|
66
|
|
|
45626
|
return 0 if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
105
|
13228
|
100
|
|
|
|
54640
|
$self->{'type'}[$axis_nr] == 2 ? 0 : 1; |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
sub axis_value_max { # --> +value |
|
109
|
9
|
|
|
9
|
0
|
33
|
my ($self, $axis_nr, $range) = @_; |
|
110
|
9
|
|
|
|
|
40
|
$range = $self->try_check_range_definition( $range ); |
|
111
|
9
|
50
|
|
|
|
37
|
return undef unless ref $range; |
|
112
|
9
|
100
|
|
|
|
34
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
113
|
8
|
|
|
|
|
41
|
return $range->[$axis_nr][1]; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
sub axis_value_min { # --> +value |
|
116
|
4
|
|
|
4
|
0
|
11
|
my ($self, $axis_nr, $range) = @_; |
|
117
|
4
|
|
|
|
|
14
|
$range = $self->try_check_range_definition( $range ); |
|
118
|
4
|
50
|
|
|
|
11
|
return undef unless ref $range; |
|
119
|
4
|
100
|
|
|
|
13
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
120
|
3
|
|
|
|
|
17
|
return $range->[$axis_nr][0]; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
sub axis_value_precision { # --> +precision? |
|
123
|
16
|
|
|
16
|
0
|
2830
|
my ($self, $axis_nr, $precision) = @_; |
|
124
|
16
|
50
|
33
|
|
|
119
|
return undef if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
125
|
16
|
100
|
|
|
|
43
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
126
|
15
|
|
33
|
|
|
105
|
$precision //= $self->{'precision'}; |
|
127
|
15
|
50
|
33
|
|
|
73
|
return undef unless ref $precision eq 'ARRAY' and exists $precision->[$axis_nr]; |
|
128
|
15
|
|
|
|
|
95
|
$precision->[$axis_nr]; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# all axis |
|
132
|
|
|
|
|
|
|
sub is_euclidean { # all axis linear ? |
|
133
|
21
|
|
|
21
|
0
|
1390
|
my ($self) = @_; |
|
134
|
21
|
100
|
|
|
|
93
|
map { return 0 if $self->{'type'}[$_] != 1 } $self->basis->axis_iterator; |
|
|
53
|
|
|
|
|
313
|
|
|
135
|
12
|
|
|
|
|
64
|
return 1; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub is_cylindrical { # one axis angular, rest linear ? |
|
139
|
21
|
|
|
21
|
0
|
60
|
my ($self) = @_; |
|
140
|
21
|
|
|
|
|
46
|
my $angular_axis = 0; |
|
141
|
21
|
100
|
|
|
|
77
|
map { $angular_axis++ if $self->{'type'}[$_] == 0; |
|
|
64
|
|
|
|
|
219
|
|
|
142
|
64
|
100
|
|
|
|
204
|
return 0 if $self->{'type'}[$_] > 1; } $self->basis->axis_iterator; |
|
143
|
20
|
100
|
|
|
|
181
|
return ($angular_axis == 1) ? 1 : 0; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub is_int_valued { # all ranges int valued ? |
|
147
|
3
|
|
|
3
|
0
|
12
|
my ($self) = @_; |
|
148
|
3
|
100
|
|
|
|
9
|
map { return 0 if $self->{'precision'}[$_] != 0 } $self->basis->axis_iterator; |
|
|
4
|
|
|
|
|
27
|
|
|
149
|
0
|
|
|
|
|
0
|
return 1; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
#### value checker ##################################################### |
|
153
|
|
|
|
|
|
|
sub check_value_shape { # $vals -- $range, $precision --> $@vals | ~! |
|
154
|
220
|
|
|
220
|
0
|
585
|
my ($self, $values, $range, $precision) = @_; |
|
155
|
220
|
100
|
|
|
|
566
|
return 'color value tuple in '.$self->basis->space_name.' space needs to be ARRAY ref with '.$self->basis->axis_count.' elements' |
|
156
|
|
|
|
|
|
|
unless $self->basis->is_value_tuple( $values ); |
|
157
|
180
|
|
|
|
|
507
|
$range = $self->try_check_range_definition( $range ); |
|
158
|
180
|
50
|
|
|
|
494
|
return $range unless ref $range; |
|
159
|
180
|
|
|
|
|
416
|
$precision = $self->try_check_precision_definition( $precision ); |
|
160
|
180
|
50
|
|
|
|
1427
|
return $precision unless ref $precision; |
|
161
|
180
|
|
|
|
|
351
|
my @names = $self->basis->long_axis_names; |
|
162
|
180
|
|
|
|
|
1324
|
for my $axis_index ($self->basis->axis_iterator){ |
|
163
|
417
|
50
|
|
|
|
821
|
next unless $self->is_axis_numeric( $axis_index ); |
|
164
|
417
|
100
|
|
|
|
1625
|
return $names[$axis_index]." value is below minimum of ".$range->[$axis_index][0] |
|
165
|
|
|
|
|
|
|
if $values->[$axis_index] < $range->[$axis_index][0]; |
|
166
|
362
|
100
|
|
|
|
1345
|
return $names[$axis_index]." value is above maximum of ".$range->[$axis_index][1] |
|
167
|
|
|
|
|
|
|
if $values->[$axis_index] > $range->[$axis_index][1]; |
|
168
|
303
|
100
|
100
|
|
|
1112
|
return $names[$axis_index]." value is not properly rounded " |
|
169
|
|
|
|
|
|
|
if $precision->[$axis_index] >= 0 |
|
170
|
|
|
|
|
|
|
and round_decimals($values->[$axis_index], $precision->[$axis_index]) != $values->[$axis_index]; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
47
|
|
|
|
|
125
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
47
|
|
|
|
|
214
|
|
|
173
|
0
|
0
|
|
|
|
0
|
return $constraint->{'error'} unless $constraint->{'checker'}->( $values ); |
|
174
|
|
|
|
|
|
|
} |
|
175
|
47
|
|
|
|
|
410
|
return $values; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub is_in_linear_bounds { # :values --> ? |
|
179
|
349
|
|
|
349
|
0
|
727
|
my ($self, $values) = @_; |
|
180
|
349
|
100
|
|
|
|
752
|
return 0 unless $self->basis->is_number_tuple( $values ); |
|
181
|
346
|
|
|
|
|
821
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
182
|
|
|
|
|
|
|
return 0 if $self->{'type'}[$axis_nr] == 1 |
|
183
|
|
|
|
|
|
|
and ( $values->[$axis_nr] < $self->{'range'}[$axis_nr][0] |
|
184
|
993
|
100
|
100
|
|
|
5431
|
or $values->[$axis_nr] > $self->{'range'}[$axis_nr][1] ); |
|
|
|
|
100
|
|
|
|
|
|
185
|
|
|
|
|
|
|
} |
|
186
|
286
|
|
|
|
|
490
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
286
|
|
|
|
|
662
|
|
|
187
|
0
|
0
|
|
|
|
0
|
return 0 unless $constraint->{'checker'}->( $values ); |
|
188
|
|
|
|
|
|
|
} |
|
189
|
286
|
|
|
|
|
841
|
return 1; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub is_equal { |
|
193
|
8
|
|
|
8
|
0
|
28
|
my ($self, $values_a, $values_b, $precision) = @_; |
|
194
|
8
|
100
|
100
|
|
|
25
|
return 0 unless $self->basis->is_value_tuple( $values_a ) and $self->basis->is_value_tuple( $values_b ); |
|
195
|
3
|
|
|
|
|
11
|
$precision = $self->try_check_precision_definition( $precision ); |
|
196
|
3
|
|
|
|
|
9
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
197
|
9
|
50
|
|
|
|
42
|
return 0 if round_decimals($values_a->[$axis_nr], $precision->[$axis_nr]) |
|
198
|
|
|
|
|
|
|
!= round_decimals($values_b->[$axis_nr], $precision->[$axis_nr]); |
|
199
|
|
|
|
|
|
|
} |
|
200
|
3
|
|
|
|
|
20
|
return 1; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
#### value ops ######################################################### |
|
204
|
|
|
|
|
|
|
sub clamp { # change values if outside of range to nearest boundary, angles get rotated into range |
|
205
|
1952
|
|
|
1952
|
0
|
15489
|
my ($self, $values, $range) = @_; |
|
206
|
1952
|
|
|
|
|
4496
|
$range = $self->try_check_range_definition( $range ); |
|
207
|
1952
|
50
|
|
|
|
4641
|
return $range unless ref $range; |
|
208
|
1952
|
50
|
|
|
|
4809
|
$values = [] unless ref $values eq 'ARRAY'; |
|
209
|
1952
|
|
|
|
|
5124
|
pop @$values while @$values > $self->basis->axis_count; |
|
210
|
1952
|
|
|
|
|
4518
|
for my $axis_nr ($self->basis->axis_iterator){ |
|
211
|
5882
|
50
|
|
|
|
11254
|
next unless $self->is_axis_numeric( $axis_nr ); # touch only numeric values |
|
212
|
5882
|
100
|
|
|
|
12729
|
if (not defined $values->[$axis_nr]){ |
|
213
|
29
|
|
|
|
|
49
|
my $default_value = 0; |
|
214
|
29
|
100
|
66
|
|
|
134
|
$default_value = $range->[$axis_nr][0] if $default_value < $range->[$axis_nr][0] |
|
215
|
|
|
|
|
|
|
or $default_value > $range->[$axis_nr][1]; |
|
216
|
29
|
|
|
|
|
54
|
$values->[$axis_nr] = $default_value; |
|
217
|
29
|
|
|
|
|
62
|
next; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
5853
|
100
|
|
|
|
11344
|
if ($self->{'type'}[$axis_nr]){ |
|
220
|
5469
|
100
|
|
|
|
13594
|
$values->[$axis_nr] = $range->[$axis_nr][0] if $values->[$axis_nr] < $range->[$axis_nr][0]; |
|
221
|
5469
|
100
|
|
|
|
14013
|
$values->[$axis_nr] = $range->[$axis_nr][1] if $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
222
|
|
|
|
|
|
|
} else { |
|
223
|
384
|
|
|
|
|
932
|
my $delta = $range->[$axis_nr][1] - $range->[$axis_nr][0]; |
|
224
|
384
|
|
|
|
|
1146
|
$values->[$axis_nr] += $delta while $values->[$axis_nr] < $range->[$axis_nr][0]; |
|
225
|
384
|
|
|
|
|
1018
|
$values->[$axis_nr] -= $delta while $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
226
|
384
|
100
|
|
|
|
1111
|
$values->[$axis_nr] = $range->[$axis_nr][0] if $values->[$axis_nr] == $range->[$axis_nr][1]; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
} |
|
229
|
1952
|
|
|
|
|
3173
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
1952
|
|
|
|
|
5549
|
|
|
230
|
0
|
0
|
|
|
|
0
|
$values = $constraint->{'remedy'}->( $values ) unless $constraint->{'checker'}->( $values ); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
1952
|
|
|
|
|
8015
|
return $values; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub round { |
|
236
|
816
|
|
|
816
|
0
|
12736
|
my ($self, $values, $precision) = @_; |
|
237
|
816
|
50
|
|
|
|
1801
|
return unless $self->basis->is_value_tuple( $values ); |
|
238
|
816
|
|
|
|
|
1867
|
$precision = $self->try_check_precision_definition( $precision ); |
|
239
|
816
|
50
|
|
|
|
1976
|
return "round got bad precision definition" unless ref $precision; |
|
240
|
816
|
100
|
66
|
|
|
1900
|
[ map { ($self->is_axis_numeric( $_ ) and $precision->[$_] >= 0) ? round_decimals ($values->[$_], $precision->[$_]) : $values->[$_] } $self->basis->axis_iterator ]; |
|
|
2455
|
|
|
|
|
4912
|
|
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# normalisation |
|
244
|
|
|
|
|
|
|
sub normalize { |
|
245
|
553
|
|
|
553
|
0
|
8291
|
my ($self, $values, $range) = @_; |
|
246
|
553
|
50
|
|
|
|
1334
|
return unless $self->basis->is_value_tuple( $values ); |
|
247
|
553
|
|
|
|
|
1594
|
$range = $self->try_check_range_definition( $range ); |
|
248
|
553
|
50
|
|
|
|
1401
|
return $range unless ref $range; |
|
249
|
553
|
50
|
|
|
|
1186
|
[ map { ($self->is_axis_numeric( $_ )) ? (($values->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0])) |
|
|
1663
|
|
|
|
|
3348
|
|
|
250
|
|
|
|
|
|
|
: $values->[$_] } $self->basis->axis_iterator ]; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub denormalize { |
|
254
|
856
|
|
|
856
|
0
|
11999
|
my ($self, $values, $range) = @_; |
|
255
|
856
|
50
|
|
|
|
2029
|
return unless $self->basis->is_value_tuple( $values ); |
|
256
|
856
|
|
|
|
|
2285
|
$range = $self->try_check_range_definition( $range ); |
|
257
|
856
|
50
|
|
|
|
2040
|
return $range unless ref $range; |
|
258
|
856
|
50
|
|
|
|
1821
|
return [ map { ($self->is_axis_numeric( $_ )) ? ($values->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0]) |
|
|
2575
|
|
|
|
|
5407
|
|
|
259
|
|
|
|
|
|
|
: $values->[$_] } $self->basis->axis_iterator ]; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub denormalize_delta { |
|
263
|
30
|
|
|
30
|
0
|
3545
|
my ($self, $delta_values, $range) = @_; |
|
264
|
30
|
50
|
|
|
|
65
|
return unless $self->basis->is_value_tuple( $delta_values ); |
|
265
|
30
|
|
|
|
|
80
|
$range = $self->try_check_range_definition( $range ); |
|
266
|
30
|
50
|
|
|
|
132
|
return $range unless ref $range; |
|
267
|
30
|
50
|
|
|
|
71
|
[ map { ($self->is_axis_numeric( $_ )) |
|
|
91
|
|
|
|
|
210
|
|
|
268
|
|
|
|
|
|
|
? ($delta_values->[$_] * ($range->[$_][1]-$range->[$_][0])) |
|
269
|
|
|
|
|
|
|
: $delta_values->[$_] } $self->basis->axis_iterator ]; |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub delta { # values have to be normalized |
|
273
|
43
|
|
|
43
|
0
|
8797
|
my ($self, $values1, $values2) = @_; |
|
274
|
43
|
100
|
100
|
|
|
141
|
return unless $self->basis->is_value_tuple( $values1 ) and $self->basis->is_value_tuple( $values2 ); |
|
275
|
|
|
|
|
|
|
# ignore none numeric dimensions |
|
276
|
37
|
50
|
|
|
|
157
|
my @delta = map { $self->is_axis_numeric($_) ? ($values2->[$_] - $values1->[$_]) : 0 } $self->basis->axis_iterator; |
|
|
112
|
|
|
|
|
872
|
|
|
277
|
37
|
100
|
|
|
|
98
|
[ map { $self->{'type'}[$_] ? $delta[$_] : # adapt to circular dimensions |
|
|
112
|
100
|
|
|
|
435
|
|
|
|
|
100
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
$delta[$_] < -0.5 ? ($delta[$_]+1) : |
|
279
|
|
|
|
|
|
|
$delta[$_] > 0.5 ? ($delta[$_]-1) : $delta[$_] } $self->basis->axis_iterator ]; |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
1; |