| 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
|
46
|
|
|
46
|
|
322569
|
use v5.12; |
|
|
46
|
|
|
|
|
213
|
|
|
6
|
46
|
|
|
46
|
|
336
|
use warnings; |
|
|
46
|
|
|
|
|
88
|
|
|
|
46
|
|
|
|
|
2771
|
|
|
7
|
46
|
|
|
46
|
|
1571
|
use Graphics::Toolkit::Color::Space::Basis; |
|
|
46
|
|
|
|
|
163
|
|
|
|
46
|
|
|
|
|
1664
|
|
|
8
|
46
|
|
|
46
|
|
337
|
use Graphics::Toolkit::Color::Space::Util qw/round_decimals is_nr/; |
|
|
46
|
|
|
|
|
144
|
|
|
|
46
|
|
|
|
|
195189
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#### constructor ####################################################### |
|
11
|
|
|
|
|
|
|
sub new { |
|
12
|
505
|
|
|
505
|
0
|
18628
|
my $pkg = shift; |
|
13
|
505
|
|
|
|
|
1821
|
my ($basis, $type, $range, $precision, $constraint) = @_; |
|
14
|
505
|
100
|
|
|
|
1547
|
return unless ref $basis eq 'Graphics::Toolkit::Color::Space::Basis'; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# expand axis type definition |
|
17
|
504
|
100
|
100
|
|
|
1675
|
if (not defined $type){ $type = [ (1) x $basis->axis_count ] } # set all axis as linear per default |
|
|
373
|
100
|
|
|
|
1057
|
|
|
18
|
|
|
|
|
|
|
elsif (ref $type eq 'ARRAY' and @$type == $basis->axis_count ) { |
|
19
|
129
|
|
|
|
|
396
|
for my $i ($basis->axis_iterator) { |
|
20
|
385
|
|
|
|
|
561
|
my $atype = $type->[$i]; # type def of this axis |
|
21
|
385
|
50
|
|
|
|
710
|
return unless defined $atype; |
|
22
|
385
|
100
|
100
|
|
|
1810
|
if ($atype eq 'angular' or $atype eq 'circular' or $atype eq '0') { $type->[$i] = 0 } |
|
|
131
|
100
|
100
|
|
|
367
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
23
|
248
|
|
|
|
|
559
|
elsif ($atype eq 'linear' or $atype eq '1') { $type->[$i] = 1 } |
|
24
|
4
|
|
|
|
|
28
|
elsif ($atype eq 'no' or $atype eq '2') { $type->[$i] = 2 } |
|
25
|
2
|
|
|
|
|
19
|
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
|
500
|
|
|
|
|
1311
|
$range = expand_range_definition(undef, $basis, $range ); |
|
30
|
500
|
100
|
|
|
|
1165
|
return $range unless ref $range; |
|
31
|
492
|
|
|
|
|
1043
|
$precision = expand_precision_definition( $basis, $precision ); |
|
32
|
492
|
100
|
|
|
|
1133
|
return $precision unless ref $precision; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# check constraint def |
|
35
|
490
|
100
|
|
|
|
917
|
if (defined $constraint){ |
|
36
|
55
|
100
|
100
|
|
|
314
|
return 'color space constraint definition has to be a none empty HASH ref' if ref $constraint ne 'HASH' or not %$constraint; |
|
37
|
53
|
|
|
|
|
175
|
for my $constraint_name (keys %$constraint){ |
|
38
|
54
|
|
|
|
|
105
|
my $properties = $constraint->{$constraint_name}; |
|
39
|
54
|
100
|
66
|
|
|
256
|
return 'a color space constraint has to be a HASH ref with three keys' unless ref $properties eq 'HASH' and keys(%$properties) == 3; |
|
40
|
52
|
|
|
|
|
230
|
$properties = {%$properties}; |
|
41
|
52
|
|
|
|
|
369
|
my $error_msg = 'constraint "$constraint_name" in '.$basis->space_name.' color space'; |
|
42
|
52
|
|
|
|
|
196
|
for (qw/checker error remedy/){ |
|
43
|
|
|
|
|
|
|
return $error_msg." needs the string-propertiy '$_'" |
|
44
|
150
|
100
|
33
|
|
|
895
|
unless exists $properties->{$_} and $properties->{$_} and not ref $properties->{$_}; |
|
|
|
|
66
|
|
|
|
|
|
45
|
|
|
|
|
|
|
} |
|
46
|
49
|
|
|
|
|
138
|
$properties->{'checker_code'} = $properties->{'checker'}; |
|
47
|
49
|
|
|
|
|
5588
|
$properties->{'checker'} = eval 'sub {'.$properties->{'checker_code'}.'}'; |
|
48
|
49
|
50
|
|
|
|
203
|
return 'checker code of '.$error_msg.":'$properties->{checker_code}' does not eval - $@" if $@; |
|
49
|
49
|
|
|
|
|
227
|
$properties->{'remedy_code'} = $properties->{'remedy'}; |
|
50
|
49
|
|
|
|
|
5718
|
$properties->{'remedy'} = eval 'sub {'.$properties->{'remedy_code'}.'}'; |
|
51
|
49
|
50
|
|
|
|
203
|
return 'remedy code of '.$error_msg.":'$properties->{remedy_code}' does not eval - $@" if $@; |
|
52
|
49
|
|
|
|
|
167
|
$constraint->{ $constraint_name } = $properties; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
435
|
|
|
|
|
736
|
} else { $constraint = '' } |
|
55
|
|
|
|
|
|
|
|
|
56
|
483
|
|
|
|
|
3415
|
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
|
1194
|
|
|
1194
|
0
|
2293
|
my ($self, $basis, $range) = @_; |
|
62
|
1194
|
50
|
|
|
|
2822
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
63
|
1194
|
|
|
|
|
1596
|
my $error_msg = 'Bad value range definition!'; |
|
64
|
1194
|
100
|
100
|
|
|
4288
|
$range = 1 if not defined $range or $range eq 'normal'; |
|
65
|
1194
|
100
|
|
|
|
2861
|
$range = 100 if $range eq 'percent'; |
|
66
|
1194
|
50
|
66
|
|
|
4265
|
return $error_msg." It has to be 'normal', 'percent', a number or ARRAY of numbers (by axis position) or HASH (by axis name).'. |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
67
|
|
|
|
|
|
|
' Instead of a number you can also insert ARRAY with two number!" |
|
68
|
|
|
|
|
|
|
unless (not ref $range and is_nr( $range )) or ref $range eq 'ARRAY' or ref $range eq 'HASH'; |
|
69
|
1194
|
100
|
|
|
|
2776
|
if (ref $range eq 'HASH') { |
|
70
|
6
|
|
|
|
|
10
|
my $range_array = []; |
|
71
|
6
|
|
|
|
|
17
|
for my $axis_name (keys %$range){ |
|
72
|
13
|
50
|
|
|
|
22
|
next unless $basis->is_axis_name( $axis_name ); |
|
73
|
13
|
|
|
|
|
24
|
$range_array->[ $basis->pos_from_axis_name($axis_name) ] = $range->{$axis_name}; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
6
|
|
|
|
|
16
|
for my $axis_index ($basis->axis_iterator){ |
|
76
|
18
|
100
|
66
|
|
|
49
|
next if exists $range_array->[$axis_index] and defined $range_array->[$axis_index]; |
|
77
|
5
|
100
|
66
|
|
|
21
|
next unless ref $self and ref $self->{'range'}; |
|
78
|
2
|
|
|
|
|
6
|
$range_array->[$axis_index] = $self->{'range'}[$axis_index]; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
6
|
|
|
|
|
12
|
$range = $range_array; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
1194
|
100
|
|
|
|
3066
|
$range = [$range] unless ref $range; |
|
83
|
1194
|
100
|
|
|
|
3884
|
$range = [(@$range) x $basis->axis_count] if @$range == 1; |
|
84
|
1194
|
100
|
|
|
|
2941
|
return "Range definition needs inside an ARRAY or HASH a number or pair of them in an ARRAY for each axis!" |
|
85
|
|
|
|
|
|
|
if @$range != $basis->axis_count; |
|
86
|
1190
|
|
|
|
|
2414
|
for my $axis_index ($basis->axis_iterator) { |
|
87
|
3594
|
|
|
|
|
5296
|
my $axis_range = $range->[$axis_index]; |
|
88
|
3594
|
100
|
|
|
|
7080
|
if (not ref $axis_range){ |
|
|
|
50
|
|
|
|
|
|
|
89
|
3165
|
100
|
|
|
|
8503
|
if ($axis_range eq 'normal') {$range->[$axis_index] = [0, 1]} |
|
|
3
|
50
|
|
|
|
13
|
|
|
90
|
0
|
|
|
|
|
0
|
elsif ($axis_range eq 'percent') {$range->[$axis_index] = [0, 100]} |
|
91
|
3162
|
|
|
|
|
6941
|
else {$range->[$axis_index] = [0, $axis_range+0]} |
|
92
|
|
|
|
|
|
|
} elsif (ref $axis_range eq 'ARRAY') { |
|
93
|
429
|
100
|
|
|
|
975
|
return $error_msg.' Array at axis number '.$axis_index.' has to have two elements' unless @$axis_range == 2; |
|
94
|
427
|
50
|
|
|
|
946
|
return $error_msg.' None numeric value at lower bound for axis number '.$axis_index unless is_nr( $axis_range->[0] ); |
|
95
|
427
|
100
|
|
|
|
918
|
return $error_msg.' None numeric value at upper bound for axis number '.$axis_index unless is_nr( $axis_range->[1] ); |
|
96
|
426
|
100
|
|
|
|
1180
|
return $error_msg.' Lower bound (first value) is >= than upper bound at axis number '.$axis_index if $axis_range->[0] >= $axis_range->[1]; |
|
97
|
0
|
|
|
|
|
0
|
} else { return "Range definitin for axis $axis_index was not an two element ARRAY!" } |
|
98
|
|
|
|
|
|
|
} |
|
99
|
1186
|
|
|
|
|
2873
|
return $range; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
sub try_check_range_definition { # check if range def is valid and eval (expand) it |
|
102
|
3252
|
|
|
3252
|
0
|
5360
|
my ($self, $range) = @_; |
|
103
|
3252
|
100
|
|
|
|
7688
|
return $self->{'range'} unless defined $range; |
|
104
|
694
|
|
|
|
|
2829
|
return $self->expand_range_definition( $self->{'basis'}, $range ); |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub expand_precision_definition { # check if precision def is valid and eval (exapand) it |
|
108
|
777
|
|
|
777
|
0
|
1548
|
my ($basis, $precision) = @_; |
|
109
|
777
|
50
|
|
|
|
2060
|
$basis = $basis->{'basis'} if ref $basis eq __PACKAGE__; |
|
110
|
777
|
100
|
|
|
|
1714
|
$precision = -1 unless defined $precision; |
|
111
|
777
|
100
|
|
|
|
2214
|
$precision = [($precision) x $basis->axis_count] unless ref $precision; |
|
112
|
777
|
50
|
|
|
|
1847
|
return 'need an ARRAY as definition of axis value precision' unless ref $precision eq 'ARRAY'; |
|
113
|
777
|
100
|
|
|
|
1796
|
return 'definition of axis value precision has to have same lengths as basis' unless @$precision == $basis->axis_count; |
|
114
|
775
|
|
|
|
|
1581
|
return $precision; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
sub try_check_precision_definition { # check if range def is valid and eval (expand) it |
|
117
|
1407
|
|
|
1407
|
0
|
2465
|
my ($self, $precision) = @_; |
|
118
|
1407
|
100
|
|
|
|
3407
|
return $self->{'precision'} unless defined $precision; |
|
119
|
285
|
|
|
|
|
736
|
return expand_precision_definition( $self->{'basis'}, $precision ); |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
#### getter of space object ############################################ |
|
123
|
9527
|
|
|
9527
|
0
|
20968
|
sub basis { $_[0]{'basis'}} |
|
124
|
|
|
|
|
|
|
# per axis |
|
125
|
|
|
|
|
|
|
sub is_axis_numeric { |
|
126
|
12010
|
|
|
12010
|
0
|
16304
|
my ($self, $axis_nr) = @_; |
|
127
|
12010
|
100
|
66
|
|
|
33086
|
return 0 if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
128
|
12006
|
100
|
|
|
|
54531
|
$self->{'type'}[$axis_nr] == 2 ? 0 : 1; |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
sub is_axis_euclidean { |
|
132
|
65
|
|
|
65
|
0
|
111
|
my ($self, $axis_nr) = @_; |
|
133
|
65
|
100
|
66
|
|
|
300
|
return 0 if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
134
|
64
|
100
|
|
|
|
187
|
$self->{'type'}[$axis_nr] == 1 ? 1 : 0; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
sub axis_value_max { # --> +value |
|
138
|
9
|
|
|
9
|
0
|
34
|
my ($self, $axis_nr, $range) = @_; |
|
139
|
9
|
|
|
|
|
40
|
$range = $self->try_check_range_definition( $range ); |
|
140
|
9
|
50
|
|
|
|
32
|
return undef unless ref $range; |
|
141
|
9
|
100
|
|
|
|
34
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
142
|
8
|
|
|
|
|
40
|
return $range->[$axis_nr][1]; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
sub axis_value_min { # --> +value |
|
145
|
4
|
|
|
4
|
0
|
13
|
my ($self, $axis_nr, $range) = @_; |
|
146
|
4
|
|
|
|
|
13
|
$range = $self->try_check_range_definition( $range ); |
|
147
|
4
|
50
|
|
|
|
13
|
return undef unless ref $range; |
|
148
|
4
|
100
|
|
|
|
13
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
149
|
3
|
|
|
|
|
19
|
return $range->[$axis_nr][0]; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
sub axis_value_precision { # --> +precision? |
|
152
|
16
|
|
|
16
|
0
|
3065
|
my ($self, $axis_nr, $precision) = @_; |
|
153
|
16
|
50
|
33
|
|
|
103
|
return undef if not defined $axis_nr or not exists $self->{'type'}[$axis_nr]; |
|
154
|
16
|
100
|
|
|
|
48
|
return undef unless $self->is_axis_numeric($axis_nr); |
|
155
|
15
|
|
33
|
|
|
82
|
$precision //= $self->{'precision'}; |
|
156
|
15
|
50
|
33
|
|
|
72
|
return undef unless ref $precision eq 'ARRAY' and exists $precision->[$axis_nr]; |
|
157
|
15
|
|
|
|
|
80
|
$precision->[$axis_nr]; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# all axis |
|
161
|
|
|
|
|
|
|
sub is_euclidean { # all axis linear ? |
|
162
|
33
|
|
|
33
|
0
|
2317
|
my ($self) = @_; |
|
163
|
33
|
100
|
|
|
|
175
|
map { return 0 if $self->{'type'}[$_] != 1 } $self->basis->axis_iterator; |
|
|
89
|
|
|
|
|
401
|
|
|
164
|
24
|
|
|
|
|
143
|
return 1; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
sub is_cylindrical { # one axis angular, rest linear ? |
|
167
|
33
|
|
|
33
|
0
|
101
|
my ($self) = @_; |
|
168
|
33
|
|
|
|
|
80
|
my $angular_axis = 0; |
|
169
|
33
|
100
|
|
|
|
135
|
map { $angular_axis++ if $self->{'type'}[$_] == 0; |
|
|
100
|
|
|
|
|
356
|
|
|
170
|
100
|
100
|
|
|
|
421
|
return 0 if $self->{'type'}[$_] > 1; } $self->basis->axis_iterator; |
|
171
|
32
|
100
|
|
|
|
506
|
return ($angular_axis == 1) ? 1 : 0; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
sub is_int_valued { # all ranges int valued ? |
|
174
|
3
|
|
|
3
|
0
|
18
|
my ($self) = @_; |
|
175
|
3
|
100
|
|
|
|
10
|
map { return 0 if $self->{'precision'}[$_] != 0 } $self->basis->axis_iterator; |
|
|
4
|
|
|
|
|
30
|
|
|
176
|
0
|
|
|
|
|
0
|
return 1; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
1348
|
100
|
|
1348
|
0
|
2166
|
sub has_constraints { my ($self) = @_; return (ref $self->{'constraint'}) ? 1 : 0 } # --> ? |
|
|
1348
|
|
|
|
|
3612
|
|
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
#### value checker ##################################################### |
|
182
|
|
|
|
|
|
|
sub check_value_shape { # @tuple -- $range, $precision --> $@vals | ~! |
|
183
|
343
|
|
|
343
|
0
|
876
|
my ($self, $tuple, $range, $precision) = @_; |
|
184
|
343
|
100
|
|
|
|
954
|
return 'color value tuple in '.$self->basis->space_name.' space needs to be ARRAY ref with '.$self->basis->axis_count.' elements' |
|
185
|
|
|
|
|
|
|
unless $self->basis->is_value_tuple( $tuple ); |
|
186
|
279
|
|
|
|
|
787
|
$range = $self->try_check_range_definition( $range ); |
|
187
|
279
|
50
|
|
|
|
822
|
return $range unless ref $range; |
|
188
|
279
|
|
|
|
|
672
|
$precision = $self->try_check_precision_definition( $precision ); |
|
189
|
279
|
50
|
|
|
|
712
|
return $precision unless ref $precision; |
|
190
|
279
|
|
|
|
|
558
|
my @names = $self->basis->long_axis_names; |
|
191
|
279
|
|
|
|
|
781
|
for my $axis_index ($self->basis->axis_iterator){ |
|
192
|
642
|
50
|
|
|
|
1436
|
next unless $self->is_axis_numeric( $axis_index ); |
|
193
|
642
|
100
|
|
|
|
2755
|
return $names[$axis_index]." value is below minimum of ".$range->[$axis_index][0] |
|
194
|
|
|
|
|
|
|
if $tuple->[$axis_index] < $range->[$axis_index][0]; |
|
195
|
551
|
100
|
|
|
|
2224
|
return $names[$axis_index]." value is above maximum of ".$range->[$axis_index][1] |
|
196
|
|
|
|
|
|
|
if $tuple->[$axis_index] > $range->[$axis_index][1]; |
|
197
|
456
|
100
|
100
|
|
|
1684
|
return $names[$axis_index]." value is not properly rounded " |
|
198
|
|
|
|
|
|
|
if $precision->[$axis_index] >= 0 |
|
199
|
|
|
|
|
|
|
and round_decimals($tuple->[$axis_index], $precision->[$axis_index]) != $tuple->[$axis_index]; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
74
|
100
|
|
|
|
290
|
if ($self->has_constraints){ |
|
202
|
9
|
|
|
|
|
47
|
my $tuple = $self->normalize($tuple, $range); |
|
203
|
9
|
|
|
|
|
17
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
9
|
|
|
|
|
28
|
|
|
204
|
9
|
100
|
|
|
|
262
|
return $constraint->{'error'} unless $constraint->{'checker'}->( $tuple ); |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
} |
|
207
|
72
|
|
|
|
|
624
|
return $tuple; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub is_equal { # @tuple_a, @tuple_b -- $precision --> ? |
|
211
|
8
|
|
|
8
|
0
|
27
|
my ($self, $tuple_a, $tuple_b, $precision) = @_; |
|
212
|
8
|
100
|
100
|
|
|
27
|
return 0 unless $self->basis->is_value_tuple( $tuple_a ) and $self->basis->is_value_tuple( $tuple_b ); |
|
213
|
3
|
|
|
|
|
10
|
$precision = $self->try_check_precision_definition( $precision ); |
|
214
|
3
|
|
|
|
|
10
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
215
|
9
|
50
|
|
|
|
23
|
return 0 if round_decimals($tuple_a->[$axis_nr], $precision->[$axis_nr]) |
|
216
|
|
|
|
|
|
|
!= round_decimals($tuple_b->[$axis_nr], $precision->[$axis_nr]); |
|
217
|
|
|
|
|
|
|
} |
|
218
|
3
|
|
|
|
|
21
|
return 1; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub is_in_constraints { # @tuple --> ? # normalized values only, so it works on any ranges |
|
222
|
2
|
|
|
2
|
0
|
7
|
my ($self, $tuple) = @_; |
|
223
|
2
|
50
|
|
|
|
8
|
return 0 unless $self->basis->is_number_tuple( $tuple ); |
|
224
|
2
|
50
|
|
|
|
7
|
return 1 unless $self->has_constraints; |
|
225
|
2
|
|
|
|
|
4
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
2
|
|
|
|
|
8
|
|
|
226
|
2
|
100
|
|
|
|
67
|
return 0 unless $constraint->{'checker'}->( $tuple ); |
|
227
|
|
|
|
|
|
|
} |
|
228
|
1
|
|
|
|
|
6
|
return 1; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub is_in_bounds { # @tuple --> ? |
|
232
|
2
|
|
|
2
|
0
|
8
|
my ($self, $tuple, $range) = @_; |
|
233
|
2
|
50
|
|
|
|
6
|
return 0 unless $self->is_in_linear_bounds( $tuple, $range ); |
|
234
|
2
|
|
|
|
|
6
|
$range = $self->try_check_range_definition( $range ); |
|
235
|
2
|
|
|
|
|
7
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
236
|
4
|
100
|
|
|
|
11
|
next if $self->{'type'}[$axis_nr]; # skip none linear axis |
|
237
|
1
|
50
|
33
|
|
|
14
|
return 0 if $tuple->[$axis_nr] < $range->[$axis_nr][0] |
|
238
|
|
|
|
|
|
|
or $tuple->[$axis_nr] > $range->[$axis_nr][1]; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
1
|
|
|
|
|
5
|
return 1; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub is_in_linear_bounds { # @tuple --> ? |
|
244
|
366
|
|
|
366
|
0
|
500
|
my ($self, $tuple, $range) = @_; |
|
245
|
366
|
100
|
|
|
|
472
|
return 0 unless $self->basis->is_number_tuple( $tuple ); |
|
246
|
363
|
|
|
|
|
610
|
$range = $self->try_check_range_definition( $range ); |
|
247
|
363
|
|
|
|
|
533
|
for my $axis_nr ($self->basis->axis_iterator) { |
|
248
|
1036
|
100
|
|
|
|
1575
|
next if $self->{'type'}[$axis_nr] != 1; # skip none linear axis |
|
249
|
953
|
100
|
100
|
|
|
2425
|
return 0 if $tuple->[$axis_nr] < $range->[$axis_nr][0] |
|
250
|
|
|
|
|
|
|
or $tuple->[$axis_nr] > $range->[$axis_nr][1]; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
297
|
50
|
|
|
|
446
|
if ($self->has_constraints){ |
|
253
|
0
|
|
|
|
|
0
|
return $self->is_in_constraints( $self->normalize( $tuple, $range) ); |
|
254
|
|
|
|
|
|
|
} |
|
255
|
297
|
|
|
|
|
593
|
return 1; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
#### value ops ######################################################### |
|
259
|
|
|
|
|
|
|
sub clamp { # change values if outside of range to nearest boundary, angles get rotated into range |
|
260
|
963
|
|
|
963
|
0
|
14457
|
my ($self, $tuple, $range) = @_; |
|
261
|
963
|
|
|
|
|
1743
|
$range = $self->try_check_range_definition( $range ); |
|
262
|
963
|
50
|
|
|
|
1900
|
return $range unless ref $range; |
|
263
|
963
|
50
|
|
|
|
2042
|
$tuple = [] unless ref $tuple eq 'ARRAY'; |
|
264
|
963
|
|
|
|
|
1971
|
pop @$tuple while @$tuple > $self->basis->axis_count; |
|
265
|
963
|
|
|
|
|
1811
|
for my $axis_nr ($self->basis->axis_iterator){ |
|
266
|
2904
|
50
|
|
|
|
4733
|
next unless $self->is_axis_numeric( $axis_nr ); # touch only numeric values |
|
267
|
2904
|
100
|
|
|
|
4810
|
if (not defined $tuple->[$axis_nr]){ |
|
268
|
80
|
|
|
|
|
441
|
my $default_value = 0; |
|
269
|
80
|
100
|
66
|
|
|
429
|
$default_value = $range->[$axis_nr][0] if $default_value < $range->[$axis_nr][0] |
|
270
|
|
|
|
|
|
|
or $default_value > $range->[$axis_nr][1]; |
|
271
|
80
|
|
|
|
|
182
|
$tuple->[$axis_nr] = $default_value; |
|
272
|
80
|
|
|
|
|
277
|
next; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
2824
|
100
|
|
|
|
4148
|
if ($self->{'type'}[$axis_nr]){ |
|
275
|
2610
|
100
|
|
|
|
5103
|
$tuple->[$axis_nr] = $range->[$axis_nr][0] if $tuple->[$axis_nr] < $range->[$axis_nr][0]; |
|
276
|
2610
|
100
|
|
|
|
5524
|
$tuple->[$axis_nr] = $range->[$axis_nr][1] if $tuple->[$axis_nr] > $range->[$axis_nr][1]; |
|
277
|
|
|
|
|
|
|
} else { |
|
278
|
214
|
|
|
|
|
417
|
my $delta = $range->[$axis_nr][1] - $range->[$axis_nr][0]; |
|
279
|
214
|
|
|
|
|
711
|
$tuple->[$axis_nr] += $delta while $tuple->[$axis_nr] < $range->[$axis_nr][0]; |
|
280
|
214
|
|
|
|
|
583
|
$tuple->[$axis_nr] -= $delta while $tuple->[$axis_nr] > $range->[$axis_nr][1]; |
|
281
|
214
|
100
|
|
|
|
580
|
$tuple->[$axis_nr] = $range->[$axis_nr][0] if $tuple->[$axis_nr] == $range->[$axis_nr][1]; |
|
282
|
|
|
|
|
|
|
} |
|
283
|
|
|
|
|
|
|
} |
|
284
|
963
|
100
|
|
|
|
2026
|
if ($self->has_constraints){ |
|
285
|
23
|
|
|
|
|
65
|
$tuple = $self->normalize( $tuple, $range); |
|
286
|
23
|
|
|
|
|
45
|
for my $constraint (values %{$self->{'constraint'}}){ |
|
|
23
|
|
|
|
|
74
|
|
|
287
|
23
|
100
|
|
|
|
653
|
$tuple = $constraint->{'remedy'}->($tuple) unless $constraint->{'checker'}->( $tuple ); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
23
|
|
|
|
|
70
|
$tuple = $self->denormalize( $tuple, $range); |
|
290
|
|
|
|
|
|
|
} |
|
291
|
963
|
|
|
|
|
3032
|
return $tuple; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub round { # $tuple -- $precision --> $tuple |
|
295
|
1125
|
|
|
1125
|
0
|
15402
|
my ($self, $tuple, $precision) = @_; |
|
296
|
1125
|
50
|
|
|
|
2120
|
return unless $self->basis->is_value_tuple( $tuple ); |
|
297
|
1125
|
|
|
|
|
2542
|
$precision = $self->try_check_precision_definition( $precision ); |
|
298
|
1125
|
50
|
|
|
|
2214
|
return "round got bad precision definition" unless ref $precision; |
|
299
|
1125
|
100
|
66
|
|
|
2078
|
[ map { ($self->is_axis_numeric( $_ ) and $precision->[$_] >= 0) ? round_decimals ($tuple->[$_], $precision->[$_]) : $tuple->[$_] } $self->basis->axis_iterator ]; |
|
|
3380
|
|
|
|
|
5387
|
|
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# normalisation |
|
303
|
|
|
|
|
|
|
sub normalize { |
|
304
|
641
|
|
|
641
|
0
|
9066
|
my ($self, $tuple, $range) = @_; |
|
305
|
641
|
50
|
|
|
|
1248
|
return unless $self->basis->is_value_tuple( $tuple ); |
|
306
|
641
|
|
|
|
|
1348
|
$range = $self->try_check_range_definition( $range ); |
|
307
|
641
|
50
|
|
|
|
1307
|
return $range unless ref $range; |
|
308
|
641
|
50
|
|
|
|
1114
|
[ map { ($self->is_axis_numeric( $_ )) ? (($tuple->[$_] - $range->[$_][0]) / ($range->[$_][1]-$range->[$_][0])) |
|
|
1927
|
|
|
|
|
2956
|
|
|
309
|
|
|
|
|
|
|
: $tuple->[$_] } $self->basis->axis_iterator ]; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub denormalize { |
|
313
|
954
|
|
|
954
|
0
|
17146
|
my ($self, $tuple, $range) = @_; |
|
314
|
954
|
50
|
|
|
|
1994
|
return unless $self->basis->is_value_tuple( $tuple ); |
|
315
|
954
|
|
|
|
|
1889
|
$range = $self->try_check_range_definition( $range ); |
|
316
|
954
|
50
|
|
|
|
1715
|
return $range unless ref $range; |
|
317
|
954
|
50
|
|
|
|
1540
|
return [ map { ($self->is_axis_numeric( $_ )) ? ($tuple->[$_] * ($range->[$_][1]-$range->[$_][0]) + $range->[$_][0]) |
|
|
2869
|
|
|
|
|
4398
|
|
|
318
|
|
|
|
|
|
|
: $tuple->[$_] } $self->basis->axis_iterator ]; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub denormalize_delta { |
|
322
|
30
|
|
|
30
|
0
|
3885
|
my ($self, $delta_values, $range) = @_; |
|
323
|
30
|
50
|
|
|
|
102
|
return unless $self->basis->is_value_tuple( $delta_values ); |
|
324
|
30
|
|
|
|
|
77
|
$range = $self->try_check_range_definition( $range ); |
|
325
|
30
|
50
|
|
|
|
68
|
return $range unless ref $range; |
|
326
|
30
|
50
|
|
|
|
85
|
[ map { ($self->is_axis_numeric( $_ )) |
|
|
91
|
|
|
|
|
166
|
|
|
327
|
|
|
|
|
|
|
? ($delta_values->[$_] * ($range->[$_][1]-$range->[$_][0])) |
|
328
|
|
|
|
|
|
|
: $delta_values->[$_] } $self->basis->axis_iterator ]; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
sub delta { # @normal_tuple_a, @normal_tuple_b --> @delta_tuple |
|
332
|
59
|
|
|
59
|
0
|
10097
|
my ($self, $tuple1, $tuple2) = @_; |
|
333
|
59
|
100
|
100
|
|
|
176
|
return unless $self->basis->is_value_tuple( $tuple1 ) and $self->basis->is_value_tuple( $tuple2 ); |
|
334
|
|
|
|
|
|
|
# ignore none numeric dimensions |
|
335
|
53
|
50
|
|
|
|
150
|
my @delta = map { $self->is_axis_numeric($_) ? ($tuple2->[$_] - $tuple1->[$_]) : 0 } $self->basis->axis_iterator; |
|
|
160
|
|
|
|
|
393
|
|
|
336
|
53
|
100
|
|
|
|
258
|
[ map { $self->{'type'}[$_] ? $delta[$_] : # adapt to circular dimensions |
|
|
160
|
100
|
|
|
|
584
|
|
|
|
|
100
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
$delta[$_] < -0.5 ? ($delta[$_]+1) : |
|
338
|
|
|
|
|
|
|
$delta[$_] > 0.5 ? ($delta[$_]-1) : $delta[$_] } $self->basis->axis_iterator ]; |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
1; |