| 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
|
|
360896
|
use v5.12; |
|
|
34
|
|
|
|
|
132
|
|
|
6
|
34
|
|
|
34
|
|
142
|
use warnings; |
|
|
34
|
|
|
|
|
56
|
|
|
|
34
|
|
|
|
|
1580
|
|
|
7
|
34
|
|
|
34
|
|
1140
|
use Graphics::Toolkit::Color::Space::Basis; |
|
|
34
|
|
|
|
|
76
|
|
|
|
34
|
|
|
|
|
902
|
|
|
8
|
34
|
|
|
34
|
|
133
|
use Graphics::Toolkit::Color::Space::Util qw/round_decimals is_nr/; |
|
|
34
|
|
|
|
|
78
|
|
|
|
34
|
|
|
|
|
105102
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#### constructor ####################################################### |
|
11
|
|
|
|
|
|
|
sub new { |
|
12
|
325
|
|
|
325
|
0
|
19989
|
my $pkg = shift; |
|
13
|
325
|
|
|
|
|
934
|
my ($basis, $type, $range, $precision, $constraint) = @_; |
|
14
|
325
|
100
|
|
|
|
2388
|
return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis'; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# expand axis type definition |
|
17
|
324
|
100
|
100
|
|
|
2617
|
if (not defined $type){ $type = [ (1) x $basis->axis_count ] } # set all axis as linear per default |
|
|
193
|
100
|
|
|
|
535
|
|
|
18
|
|
|
|
|
|
|
elsif (ref $type eq 'ARRAY' and @$type == $basis->axis_count ) { |
|
19
|
129
|
|
|
|
|
285
|
for my $i ($basis->axis_iterator) { |
|
20
|
385
|
|
|
|
|
507
|
my $atype = $type->[$i]; # type def of this axis |
|
21
|
385
|
50
|
|
|
|
551
|
return unless defined $atype; |
|
22
|
385
|
100
|
100
|
|
|
1532
|
if ($atype eq 'angular' or $atype eq 'circular' or $atype eq '0') { $type->[$i] = 0 } |
|
|
131
|
100
|
100
|
|
|
281
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
23
|
248
|
|
|
|
|
399
|
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
|
|
|
|
|
8
|
} else { return 'invalid axis type definition in color space '.$basis->space_name } |
|
28
|
|
|
|
|
|
|
|
|
29
|
320
|
|
|
|
|
793
|
$range = expand_range_definition( $basis, $range ); |
|
30
|
320
|
100
|
|
|
|
695
|
return $range unless ref $range; |
|
31
|
312
|
|
|
|
|
632
|
$precision = expand_precision_definition( $basis, $precision ); |
|
32
|
312
|
100
|
|
|
|
508
|
return $precision unless ref $precision; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# check constraint def |
|
35
|
310
|
100
|
|
|
|
495
|
if (defined $constraint){ |
|
36
|
40
|
100
|
100
|
|
|
211
|
return 'color space constraint definition has to be a none empty HASH ref' if ref $constraint ne 'HASH' or not %$constraint; |
|
37
|
38
|
|
|
|
|
125
|
for my $constraint_name (keys %$constraint){ |
|
38
|
39
|
|
|
|
|
68
|
my $properties = $constraint->{$constraint_name}; |
|
39
|
39
|
100
|
66
|
|
|
175
|
return 'a color space constraint has to be a HASH ref with three keys' unless ref $properties eq 'HASH' and keys(%$properties) == 3; |
|
40
|
37
|
|
|
|
|
135
|
$properties = {%$properties}; |
|
41
|
37
|
|
|
|
|
97
|
my $error_msg = 'constraint "$constraint_name" in '.$basis->space_name.' color space'; |
|
42
|
37
|
|
|
|
|
201
|
for (qw/checker error remedy/){ |
|
43
|
|
|
|
|
|
|
return $error_msg." needs the string-propertiy '$_'" |
|
44
|
105
|
100
|
33
|
|
|
635
|
unless exists $properties->{$_} and $properties->{$_} and not ref $properties->{$_}; |
|
|
|
|
66
|
|
|
|
|
|
45
|
|
|
|
|
|
|
} |
|
46
|
34
|
|
|
|
|
98
|
$properties->{'checker_code'} = $properties->{'checker'}; |
|
47
|
34
|
|
|
|
|
3227
|
$properties->{'checker'} = eval 'sub {'.$properties->{'checker_code'}.'}'; |
|
48
|
34
|
50
|
|
|
|
151
|
return 'checker code of '.$error_msg.":'$properties->{checker_code}' does not eval - $@" if $@; |
|
49
|
34
|
|
|
|
|
79
|
$properties->{'remedy_code'} = $properties->{'remedy'}; |
|
50
|
34
|
|
|
|
|
2932
|
$properties->{'remedy'} = eval 'sub {'.$properties->{'remedy_code'}.'}'; |
|
51
|
34
|
50
|
|
|
|
158
|
return 'remedy code of '.$error_msg.":'$properties->{remedy_code}' does not eval - $@" if $@; |
|
52
|
34
|
|
|
|
|
94
|
$constraint->{ $constraint_name } = $properties; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
270
|
|
|
|
|
433
|
} else { $constraint = '' } |
|
55
|
|
|
|
|
|
|
|
|
56
|
303
|
|
|
|
|
1576
|
bless { basis => $basis, type => $type, range => $range, precision => $precision, constraint => $constraint } |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
#### object attribute checker ########################################## |
|
60
|
|
|
|
|
|
|
sub expand_range_definition { # check if range def is valid and eval (expand) it |
|
61
|
1572
|
|
|
1572
|
0
|
2201
|
my ($basis, $range) = @_; |
|
62
|
1572
|
50
|
|
|
|
2934
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
63
|
1572
|
|
|
|
|
1763
|
my $error_msg = 'Bad value range definition!'; |
|
64
|
1572
|
100
|
100
|
|
|
4417
|
$range = 1 if not defined $range or $range eq 'normal'; |
|
65
|
1572
|
100
|
|
|
|
6795
|
$range = 100 if $range eq 'percent'; |
|
66
|
1572
|
100
|
66
|
|
|
4262
|
return $error_msg." It has to be 'normal', 'percent', a number or ARRAY of numbers or ARRAY of ARRAY's with two number!" |
|
|
|
|
100
|
|
|
|
|
|
67
|
|
|
|
|
|
|
unless (not ref $range and is_nr( $range )) or (ref $range eq 'ARRAY') ; |
|
68
|
1571
|
100
|
|
|
|
3580
|
$range = [$range] unless ref $range; |
|
69
|
1571
|
100
|
|
|
|
3466
|
$range = [(@$range) x $basis->axis_count] if @$range == 1; |
|
70
|
1571
|
100
|
|
|
|
2908
|
return "Range definition needs inside an ARRAY either one definition for all axis or one definition". |
|
71
|
|
|
|
|
|
|
" for each axis!" if @$range != $basis->axis_count; |
|
72
|
1568
|
|
|
|
|
2423
|
for my $axis_index ($basis->axis_iterator) { |
|
73
|
4735
|
|
|
|
|
5118
|
my $axis_range = $range->[$axis_index]; |
|
74
|
4735
|
100
|
|
|
|
5858
|
if (not ref $axis_range){ |
|
|
|
50
|
|
|
|
|
|
|
75
|
4335
|
100
|
|
|
|
6588
|
if ($axis_range eq 'normal') {$range->[$axis_index] = [0, 1]} |
|
|
3
|
50
|
|
|
|
13
|
|
|
76
|
0
|
|
|
|
|
0
|
elsif ($axis_range eq 'percent') {$range->[$axis_index] = [0, 100]} |
|
77
|
4332
|
|
|
|
|
7153
|
else {$range->[$axis_index] = [0, $axis_range+0]} |
|
78
|
|
|
|
|
|
|
} elsif (ref $axis_range eq 'ARRAY') { |
|
79
|
400
|
100
|
|
|
|
696
|
return $error_msg.' Array at axis number '.$axis_index.' has to have two elements' unless @$axis_range == 2; |
|
80
|
398
|
50
|
|
|
|
770
|
return $error_msg.' None numeric value at lower bound for axis number '.$axis_index unless is_nr( $axis_range->[0] ); |
|
81
|
398
|
100
|
|
|
|
716
|
return $error_msg.' None numeric value at upper bound for axis number '.$axis_index unless is_nr( $axis_range->[1] ); |
|
82
|
397
|
100
|
|
|
|
916
|
return $error_msg.' Lower bound (first value) is >= than upper bound at axis number '.$axis_index if $axis_range->[0] >= $axis_range->[1]; |
|
83
|
0
|
|
|
|
|
0
|
} else { return "Range definitin for axis $axis_index was not an two element ARRAY!" } |
|
84
|
|
|
|
|
|
|
} |
|
85
|
1564
|
|
|
|
|
2912
|
return $range; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
sub try_check_range_definition { # check if range def is valid and eval (expand) it |
|
88
|
4085
|
|
|
4085
|
0
|
5446
|
my ($self, $range) = @_; |
|
89
|
4085
|
100
|
|
|
|
7599
|
return $self->{'range'} unless defined $range; |
|
90
|
1252
|
|
|
|
|
2020
|
return expand_range_definition( $self->{'basis'}, $range ); |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub expand_precision_definition { # check if precision def is valid and eval (exapand) it |
|
94
|
321
|
|
|
321
|
0
|
532
|
my ($basis, $precision) = @_; |
|
95
|
321
|
50
|
|
|
|
697
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
96
|
321
|
100
|
|
|
|
2815
|
$precision = -1 unless defined $precision; |
|
97
|
321
|
100
|
|
|
|
4568
|
$precision = [($precision) x $basis->axis_count] unless ref $precision; |
|
98
|
321
|
50
|
|
|
|
688
|
return 'need an ARRAY as definition of axis value precision' unless ref $precision eq 'ARRAY'; |
|
99
|
321
|
100
|
|
|
|
539
|
return 'definition of axis value precision has to have same lengths as basis' unless @$precision == $basis->axis_count; |
|
100
|
319
|
|
|
|
|
546
|
return $precision; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
sub try_check_precision_definition { # check if range def is valid and eval (expand) it |
|
103
|
1515
|
|
|
1515
|
0
|
1886
|
my ($self, $precision) = @_; |
|
104
|
1515
|
100
|
|
|
|
2921
|
return $self->{'precision'} unless defined $precision; |
|
105
|
9
|
|
|
|
|
26
|
return expand_precision_definition( $self->{'basis'}, $precision ); |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
#### getter of space object ############################################ |
|
109
|
11322
|
|
|
11322
|
0
|
19197
|
sub basis { $_[0]{'basis'}} |
|
110
|
|
|
|
|
|
|
# per axis |
|
111
|
|
|
|
|
|
|
sub is_axis_numeric { |
|
112
|
15197
|
|
|
15197
|
0
|
16841
|
my ($self, $axis_nr) = @_; |
|
113
|
15197
|
100
|
66
|
|
|
31932
|
return 0 if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
114
|
15193
|
100
|
|
|
|
39541
|
$self->{'type'}[$axis_nr] == 2 ? 0 : 1; |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
sub is_axis_euclidean { |
|
118
|
65
|
|
|
65
|
0
|
101
|
my ($self, $axis_nr) = @_; |
|
119
|
65
|
100
|
66
|
|
|
219
|
return 0 if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
120
|
64
|
100
|
|
|
|
132
|
$self->{'type'}[$axis_nr] == 1 ? 1 : 0; |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
sub axis_value_max { # --> +value |
|
124
|
9
|
|
|
9
|
0
|
49
|
my ($self, $axis_nr, $range) = @_; |
|
125
|
9
|
|
|
|
|
37
|
$range = $self->try_check_range_definition( $range ); |
|
126
|
9
|
50
|
|
|
|
43
|
return undef unless ref $range; |
|
127
|
9
|
100
|
|
|
|
28
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
128
|
8
|
|
|
|
|
36
|
return $range->[$axis_nr][1]; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
sub axis_value_min { # --> +value |
|
131
|
4
|
|
|
4
|
0
|
14
|
my ($self, $axis_nr, $range) = @_; |
|
132
|
4
|
|
|
|
|
13
|
$range = $self->try_check_range_definition( $range ); |
|
133
|
4
|
50
|
|
|
|
39
|
return undef unless ref $range; |
|
134
|
4
|
100
|
|
|
|
12
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
135
|
3
|
|
|
|
|
37
|
return $range->[$axis_nr][0]; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
sub axis_value_precision { # --> +precision? |
|
138
|
16
|
|
|
16
|
0
|
2931
|
my ($self, $axis_nr, $precision) = @_; |
|
139
|
16
|
50
|
33
|
|
|
101
|
return undef if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
140
|
16
|
100
|
|
|
|
39
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
141
|
15
|
|
33
|
|
|
79
|
$precision //= $self->{'precision'}; |
|
142
|
15
|
50
|
33
|
|
|
64
|
return undef unless ref $precision eq 'ARRAY' and exists $precision->[$axis_nr]; |
|
143
|
15
|
|
|
|
|
81
|
$precision->[$axis_nr]; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# all axis |
|
147
|
|
|
|
|
|
|
sub is_euclidean { # all axis linear ? |
|
148
|
21
|
|
|
21
|
0
|
1932
|
my ($self) = @_; |
|
149
|
21
|
100
|
|
|
|
87
|
map { return 0 if $self->{'type'}[$_] != 1 } $self->basis->axis_iterator; |
|
|
53
|
|
|
|
|
213
|
|
|
150
|
12
|
|
|
|
|
77
|
return 1; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub is_cylindrical { # one axis angular, rest linear ? |
|
154
|
21
|
|
|
21
|
0
|
91
|
my ($self) = @_; |
|
155
|
21
|
|
|
|
|
48
|
my $angular_axis = 0; |
|
156
|
21
|
100
|
|
|
|
72
|
map { $angular_axis++ if $self->{'type'}[$_] == 0; |
|
|
64
|
|
|
|
|
205
|
|
|
157
|
64
|
100
|
|
|
|
182
|
return 0 if $self->{'type'}[$_] > 1; } $self->basis->axis_iterator; |
|
158
|
20
|
100
|
|
|
|
135
|
return ($angular_axis == 1) ? 1 : 0; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub is_int_valued { # all ranges int valued ? |
|
162
|
3
|
|
|
3
|
0
|
15
|
my ($self) = @_; |
|
163
|
3
|
100
|
|
|
|
10
|
map { return 0 if $self->{'precision'}[$_] != 0 } $self->basis->axis_iterator; |
|
|
4
|
|
|
|
|
31
|
|
|
164
|
0
|
|
|
|
|
0
|
return 1; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
#### value checker ##################################################### |
|
168
|
|
|
|
|
|
|
sub check_value_shape { # $vals -- $range, $precision --> $@vals | ~! |
|
169
|
222
|
|
|
222
|
0
|
504
|
my ($self, $values, $range, $precision) = @_; |
|
170
|
222
|
100
|
|
|
|
499
|
return 'color value tuple in '.$self->basis->space_name.' space needs to be ARRAY ref with '.$self->basis->axis_count.' elements' |
|
171
|
|
|
|
|
|
|
unless $self->basis->is_value_tuple( $values ); |
|
172
|
182
|
|
|
|
|
447
|
$range = $self->try_check_range_definition( $range ); |
|
173
|
182
|
50
|
|
|
|
382
|
return $range unless ref $range; |
|
174
|
182
|
|
|
|
|
379
|
$precision = $self->try_check_precision_definition( $precision ); |
|
175
|
182
|
50
|
|
|
|
351
|
return $precision unless ref $precision; |
|
176
|
182
|
|
|
|
|
2067
|
my @names = $self->basis->long_axis_names; |
|
177
|
182
|
|
|
|
|
380
|
for my $axis_index ($self->basis->axis_iterator){ |
|
178
|
423
|
50
|
|
|
|
759
|
next unless $self->is_axis_numeric( $axis_index ); |
|
179
|
423
|
100
|
|
|
|
1402
|
return $names[$axis_index]." value is below minimum of ".$range->[$axis_index][0] |
|
180
|
|
|
|
|
|
|
if $values->[$axis_index] < $range->[$axis_index][0]; |
|
181
|
368
|
100
|
|
|
|
1214
|
return $names[$axis_index]." value is above maximum of ".$range->[$axis_index][1] |
|
182
|
|
|
|
|
|
|
if $values->[$axis_index] > $range->[$axis_index][1]; |
|
183
|
309
|
100
|
100
|
|
|
1033
|
return $names[$axis_index]." value is not properly rounded " |
|
184
|
|
|
|
|
|
|
if $precision->[$axis_index] >= 0 |
|
185
|
|
|
|
|
|
|
and round_decimals($values->[$axis_index], $precision->[$axis_index]) != $values->[$axis_index]; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
49
|
100
|
|
|
|
147
|
if ($self->has_constraints){ |
|
188
|
6
|
|
|
|
|
20
|
my $values = $self->normalize($values, $range); |
|
189
|
6
|
|
|
|
|
8
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
6
|
|
|
|
|
17
|
|
|
190
|
6
|
100
|
|
|
|
162
|
return $constraint->{'error'} unless $constraint->{'checker'}->( $values ); |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} |
|
193
|
48
|
|
|
|
|
322
|
return $values; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub is_equal { # @values_a, @values_b -- $precision --> ? |
|
197
|
8
|
|
|
8
|
0
|
47
|
my ($self, $values_a, $values_b, $precision) = @_; |
|
198
|
8
|
100
|
100
|
|
|
21
|
return 0 unless $self->basis->is_value_tuple( $values_a ) and $self->basis->is_value_tuple( $values_b ); |
|
199
|
3
|
|
|
|
|
60
|
$precision = $self->try_check_precision_definition( $precision ); |
|
200
|
3
|
|
|
|
|
9
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
201
|
9
|
50
|
|
|
|
27
|
return 0 if round_decimals($values_a->[$axis_nr], $precision->[$axis_nr]) |
|
202
|
|
|
|
|
|
|
!= round_decimals($values_b->[$axis_nr], $precision->[$axis_nr]); |
|
203
|
|
|
|
|
|
|
} |
|
204
|
3
|
|
|
|
|
18
|
return 1; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
1861
|
100
|
|
1861
|
0
|
2289
|
sub has_constraints { my ($self) = @_; return (ref $self->{'constraint'}) ? 1 : 0 } # --> ? |
|
|
1861
|
|
|
|
|
4086
|
|
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub is_in_constraints { # @values --> ? # normalized values only, so it works on any ranges |
|
210
|
2
|
|
|
2
|
0
|
6
|
my ($self, $values) = @_; |
|
211
|
2
|
50
|
|
|
|
8
|
return 1 unless $self->has_constraints; |
|
212
|
2
|
|
|
|
|
4
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
2
|
|
|
|
|
10
|
|
|
213
|
2
|
100
|
|
|
|
64
|
return 0 unless $constraint->{'checker'}->( $values ); |
|
214
|
|
|
|
|
|
|
} |
|
215
|
1
|
|
|
|
|
6
|
return 1; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub is_in_bounds { # :values --> ? |
|
219
|
6
|
|
|
6
|
0
|
19
|
my ($self, $values, $range) = @_; |
|
220
|
6
|
50
|
|
|
|
24
|
return 0 unless $self->basis->is_number_tuple( $values ); |
|
221
|
6
|
|
|
|
|
26
|
$range = $self->try_check_range_definition( $range ); |
|
222
|
6
|
|
|
|
|
17
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
223
|
12
|
50
|
|
|
|
56
|
next if $self->{'type'}[$axis_nr] > 1; # skip none numeric axis |
|
224
|
12
|
100
|
66
|
|
|
86
|
return 0 if $values->[$axis_nr] < $range->[$axis_nr][0] |
|
225
|
|
|
|
|
|
|
or $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
226
|
|
|
|
|
|
|
} |
|
227
|
3
|
50
|
|
|
|
16
|
if ($self->has_constraints){ |
|
228
|
0
|
|
|
|
|
0
|
return $self->is_in_constraints( $self->normalize( $values, $range) ); |
|
229
|
|
|
|
|
|
|
} |
|
230
|
3
|
|
|
|
|
26
|
return 1; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub is_in_linear_bounds { # :values --> ? |
|
234
|
349
|
|
|
349
|
0
|
494
|
my ($self, $values, $range) = @_; |
|
235
|
349
|
100
|
|
|
|
500
|
return 0 unless $self->basis->is_number_tuple( $values ); |
|
236
|
346
|
|
|
|
|
549
|
$range = $self->try_check_range_definition( $range ); |
|
237
|
346
|
|
|
|
|
491
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
238
|
993
|
100
|
|
|
|
1535
|
next if $self->{'type'}[$axis_nr] != 1; # skip none linear axis |
|
239
|
919
|
100
|
100
|
|
|
2546
|
return 0 if $values->[$axis_nr] < $range->[$axis_nr][0] |
|
240
|
|
|
|
|
|
|
or $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
286
|
50
|
|
|
|
505
|
if ($self->has_constraints){ |
|
243
|
0
|
|
|
|
|
0
|
return $self->is_in_constraints( $self->normalize( $values, $range) ); |
|
244
|
|
|
|
|
|
|
} |
|
245
|
286
|
|
|
|
|
551
|
return 1; |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
#### value ops ######################################################### |
|
249
|
|
|
|
|
|
|
sub clamp { # change values if outside of range to nearest boundary, angles get rotated into range |
|
250
|
1517
|
|
|
1517
|
0
|
14747
|
my ($self, $values, $range) = @_; |
|
251
|
1517
|
|
|
|
|
2243
|
$range = $self->try_check_range_definition( $range ); |
|
252
|
1517
|
50
|
|
|
|
2320
|
return $range unless ref $range; |
|
253
|
1517
|
50
|
|
|
|
2521
|
$values = [] unless ref $values eq 'ARRAY'; |
|
254
|
1517
|
|
|
|
|
2490
|
pop @$values while @$values > $self->basis->axis_count; |
|
255
|
1517
|
|
|
|
|
2081
|
for my $axis_nr ($self->basis->axis_iterator){ |
|
256
|
4574
|
50
|
|
|
|
5757
|
next unless $self->is_axis_numeric( $axis_nr ); # touch only numeric values |
|
257
|
4574
|
100
|
|
|
|
6036
|
if (not defined $values->[$axis_nr]){ |
|
258
|
29
|
|
|
|
|
50
|
my $default_value = 0; |
|
259
|
29
|
100
|
66
|
|
|
148
|
$default_value = $range->[$axis_nr][0] if $default_value < $range->[$axis_nr][0] |
|
260
|
|
|
|
|
|
|
or $default_value > $range->[$axis_nr][1]; |
|
261
|
29
|
|
|
|
|
60
|
$values->[$axis_nr] = $default_value; |
|
262
|
29
|
|
|
|
|
94
|
next; |
|
263
|
|
|
|
|
|
|
} |
|
264
|
4545
|
100
|
|
|
|
5541
|
if ($self->{'type'}[$axis_nr]){ |
|
265
|
4260
|
100
|
|
|
|
6726
|
$values->[$axis_nr] = $range->[$axis_nr][0] if $values->[$axis_nr] < $range->[$axis_nr][0]; |
|
266
|
4260
|
100
|
|
|
|
6886
|
$values->[$axis_nr] = $range->[$axis_nr][1] if $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
267
|
|
|
|
|
|
|
} else { |
|
268
|
285
|
|
|
|
|
459
|
my $delta = $range->[$axis_nr][1] - $range->[$axis_nr][0]; |
|
269
|
285
|
|
|
|
|
609
|
$values->[$axis_nr] += $delta while $values->[$axis_nr] < $range->[$axis_nr][0]; |
|
270
|
285
|
|
|
|
|
556
|
$values->[$axis_nr] -= $delta while $values->[$axis_nr] > $range->[$axis_nr][1]; |
|
271
|
285
|
100
|
|
|
|
560
|
$values->[$axis_nr] = $range->[$axis_nr][0] if $values->[$axis_nr] == $range->[$axis_nr][1]; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
} |
|
274
|
1517
|
100
|
|
|
|
2732
|
if ($self->has_constraints){ |
|
275
|
20
|
|
|
|
|
67
|
$values = $self->normalize( $values, $range); |
|
276
|
20
|
|
|
|
|
38
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
20
|
|
|
|
|
53
|
|
|
277
|
20
|
100
|
|
|
|
475
|
$values = $constraint->{'remedy'}->($values) unless $constraint->{'checker'}->( $values ); |
|
278
|
|
|
|
|
|
|
} |
|
279
|
20
|
|
|
|
|
58
|
$values = $self->denormalize( $values, $range); |
|
280
|
|
|
|
|
|
|
} |
|
281
|
1517
|
|
|
|
|
3752
|
return $values; |
|
282
|
|
|
|
|
|
|
} |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub round { |
|
285
|
1330
|
|
|
1330
|
0
|
16907
|
my ($self, $values, $precision) = @_; |
|
286
|
1330
|
50
|
|
|
|
1669
|
return unless $self->basis->is_value_tuple( $values ); |
|
287
|
1330
|
|
|
|
|
1939
|
$precision = $self->try_check_precision_definition( $precision ); |
|
288
|
1330
|
50
|
|
|
|
1870
|
return "round got bad precision definition" unless ref $precision; |
|
289
|
1330
|
100
|
66
|
|
|
1732
|
[ map { ($self->is_axis_numeric( $_ ) and $precision->[$_] >= 0) ? round_decimals ($values->[$_], $precision->[$_]) : $values->[$_] } $self->basis->axis_iterator ]; |
|
|
3997
|
|
|
|
|
4647
|
|
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# normalisation |
|
293
|
|
|
|
|
|
|
sub normalize { |
|
294
|
594
|
|
|
594
|
0
|
6294
|
my ($self, $values, $range) = @_; |
|
295
|
594
|
50
|
|
|
|
1125
|
return unless $self->basis->is_value_tuple( $values ); |
|
296
|
594
|
|
|
|
|
1055
|
$range = $self->try_check_range_definition( $range ); |
|
297
|
594
|
50
|
|
|
|
1082
|
return $range unless ref $range; |
|
298
|
594
|
50
|
|
|
|
913
|
[ map { ($self->is_axis_numeric( $_ )) ? (($values->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0])) |
|
|
1786
|
|
|
|
|
2361
|
|
|
299
|
|
|
|
|
|
|
: $values->[$_] } $self->basis->axis_iterator ]; |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub denormalize { |
|
303
|
1390
|
|
|
1390
|
0
|
11516
|
my ($self, $values, $range) = @_; |
|
304
|
1390
|
50
|
|
|
|
2181
|
return unless $self->basis->is_value_tuple( $values ); |
|
305
|
1390
|
|
|
|
|
2182
|
$range = $self->try_check_range_definition( $range ); |
|
306
|
1390
|
50
|
|
|
|
2131
|
return $range unless ref $range; |
|
307
|
1390
|
50
|
|
|
|
1894
|
return [ map { ($self->is_axis_numeric( $_ )) ? ($values->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0]) |
|
|
4177
|
|
|
|
|
5168
|
|
|
308
|
|
|
|
|
|
|
: $values->[$_] } $self->basis->axis_iterator ]; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub denormalize_delta { |
|
312
|
30
|
|
|
30
|
0
|
3834
|
my ($self, $delta_values, $range) = @_; |
|
313
|
30
|
50
|
|
|
|
57
|
return unless $self->basis->is_value_tuple( $delta_values ); |
|
314
|
30
|
|
|
|
|
68
|
$range = $self->try_check_range_definition( $range ); |
|
315
|
30
|
50
|
|
|
|
73
|
return $range unless ref $range; |
|
316
|
30
|
50
|
|
|
|
75
|
[ map { ($self->is_axis_numeric( $_ )) |
|
|
91
|
|
|
|
|
153
|
|
|
317
|
|
|
|
|
|
|
? ($delta_values->[$_] * ($range->[$_][1]-$range->[$_][0])) |
|
318
|
|
|
|
|
|
|
: $delta_values->[$_] } $self->basis->axis_iterator ]; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub delta { # values have to be normalized |
|
322
|
43
|
|
|
43
|
0
|
10156
|
my ($self, $values1, $values2) = @_; |
|
323
|
43
|
100
|
100
|
|
|
159
|
return unless $self->basis->is_value_tuple( $values1 ) and $self->basis->is_value_tuple( $values2 ); |
|
324
|
|
|
|
|
|
|
# ignore none numeric dimensions |
|
325
|
37
|
50
|
|
|
|
94
|
my @delta = map { $self->is_axis_numeric($_) ? ($values2->[$_] - $values1->[$_]) : 0 } $self->basis->axis_iterator; |
|
|
112
|
|
|
|
|
214
|
|
|
326
|
37
|
100
|
|
|
|
90
|
[ map { $self->{'type'}[$_] ? $delta[$_] : # adapt to circular dimensions |
|
|
112
|
100
|
|
|
|
389
|
|
|
|
|
100
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
$delta[$_] < -0.5 ? ($delta[$_]+1) : |
|
328
|
|
|
|
|
|
|
$delta[$_] > 0.5 ? ($delta[$_]-1) : $delta[$_] } $self->basis->axis_iterator ]; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
1; |