line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::BSpline::Curve::Role::Approximation; |
2
|
|
|
|
|
|
|
$Math::BSpline::Curve::Role::Approximation::VERSION = '0.002'; |
3
|
|
|
|
|
|
|
# ABSTRACT: fitting a B-spline curve to a point set |
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
49804
|
use 5.014; |
|
5
|
|
|
|
|
20
|
|
6
|
5
|
|
|
5
|
|
30
|
use warnings; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
150
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
29
|
use Moo::Role; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
27
|
|
9
|
5
|
|
|
5
|
|
1953
|
use List::Util 1.26 ('sum0'); |
|
5
|
|
|
|
|
162
|
|
|
5
|
|
|
|
|
413
|
|
10
|
5
|
|
|
5
|
|
38
|
use Scalar::Util 1.26 ('blessed'); |
|
5
|
|
|
|
|
111
|
|
|
5
|
|
|
|
|
297
|
|
11
|
5
|
|
|
5
|
|
35
|
use Ref::Util 0.010 ('is_plain_arrayref'); |
|
5
|
|
|
|
|
76
|
|
|
5
|
|
|
|
|
311
|
|
12
|
5
|
|
|
5
|
|
46
|
use Module::Runtime 0.012 ('require_module'); |
|
5
|
|
|
|
|
146
|
|
|
5
|
|
|
|
|
46
|
|
13
|
5
|
|
|
5
|
|
314
|
use Math::BSpline::Basis 0.001; |
|
5
|
|
|
|
|
72
|
|
|
5
|
|
|
|
|
167
|
|
14
|
5
|
|
|
5
|
|
2623
|
use Math::Matrix::Banded 0.004; |
|
5
|
|
|
|
|
106624
|
|
|
5
|
|
|
|
|
10741
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
requires ( |
17
|
|
|
|
|
|
|
'new', |
18
|
|
|
|
|
|
|
); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub fit { |
22
|
3
|
|
|
3
|
0
|
3387
|
my ($class, @args) = @_; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# We support both a hash and a hashref as args. |
25
|
3
|
50
|
|
|
|
20
|
my $args = @args == 1 ? $args[0] : {@args}; |
26
|
3
|
|
50
|
|
|
15
|
$args ||= {}; |
27
|
|
|
|
|
|
|
|
28
|
3
|
|
|
|
|
9
|
foreach ('degree', 'n_control_points', 'points') { |
29
|
9
|
50
|
|
|
|
27
|
if (!exists($args->{$_})) { |
30
|
0
|
|
|
|
|
0
|
$Math::BSpline::Curve::logger->error( |
31
|
|
|
|
|
|
|
"Missing required arguments: $_", |
32
|
|
|
|
|
|
|
); |
33
|
0
|
|
|
|
|
0
|
return undef; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
3
|
|
|
|
|
13
|
my $apr = $class->_fit_approximate_unbounded($args); |
38
|
3
|
50
|
|
|
|
54
|
if ($apr) { |
39
|
|
|
|
|
|
|
return $class->new( |
40
|
|
|
|
|
|
|
degree => $args->{degree}, |
41
|
|
|
|
|
|
|
knot_vector => $apr->{knot_vector}, |
42
|
|
|
|
|
|
|
control_points => $apr->{control_points}, |
43
|
3
|
|
|
|
|
92
|
); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
else { |
46
|
0
|
|
|
|
|
0
|
return undef; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub calculate_parameters { |
52
|
2
|
|
|
2
|
0
|
7
|
my ($class, $points, $lengths, $total_length) = @_; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# We support omission of $lengths/$total_length or only of |
55
|
|
|
|
|
|
|
# $total_length. |
56
|
2
|
50
|
|
|
|
10
|
($lengths, $total_length) = $class->_fit_calculate_lengths($points) |
57
|
|
|
|
|
|
|
if (!$lengths); |
58
|
2
|
|
33
|
|
|
7
|
$total_length //= sum0(@$lengths); |
59
|
|
|
|
|
|
|
|
60
|
2
|
|
|
|
|
4
|
my $phi = [0]; |
61
|
2
|
|
|
|
|
4
|
my $cur_phi = 0; |
62
|
2
|
|
|
|
|
10
|
for (my $i=1;$i<@$points-1;$i++) { |
63
|
396
|
|
|
|
|
612
|
$cur_phi += $lengths->[$i-1] / $total_length; |
64
|
396
|
|
|
|
|
829
|
push(@$phi, $cur_phi); |
65
|
|
|
|
|
|
|
} |
66
|
2
|
|
|
|
|
4
|
push(@$phi, 1); |
67
|
|
|
|
|
|
|
|
68
|
2
|
|
|
|
|
18
|
return $phi; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub _fit_approximate_unbounded { |
73
|
3
|
|
|
3
|
|
8
|
my ($class, $args) = @_; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
my $phi = $args->{phi} // $class->calculate_parameters( |
76
|
|
|
|
|
|
|
$args->{points}, |
77
|
3
|
|
66
|
|
|
14
|
); |
78
|
|
|
|
|
|
|
my $U = $args->{knot_vector} // $class->_fit_calculate_knot_vector( |
79
|
|
|
|
|
|
|
$args->{degree}, |
80
|
3
|
|
33
|
|
|
21
|
$args->{n_control_points} - 1, |
81
|
|
|
|
|
|
|
$phi, |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# We have not constructed the curve object, yet. Hence, we need |
85
|
|
|
|
|
|
|
# construct our own basis. |
86
|
|
|
|
|
|
|
my $basis = Math::BSpline::Basis->new( |
87
|
|
|
|
|
|
|
degree => $args->{degree}, |
88
|
3
|
|
|
|
|
65
|
knot_vector => $U, |
89
|
|
|
|
|
|
|
); |
90
|
|
|
|
|
|
|
|
91
|
3
|
|
|
|
|
2253
|
my $Nt = $class->_fit_calculate_Nt( |
92
|
|
|
|
|
|
|
$basis, |
93
|
|
|
|
|
|
|
$phi, |
94
|
|
|
|
|
|
|
); |
95
|
3
|
|
|
|
|
17
|
my $NtN = $Nt->AAt; |
96
|
3
|
|
|
|
|
103813
|
my $result = $NtN->decompose_LU; |
97
|
3
|
50
|
|
|
|
98484
|
if (!$result) { |
98
|
0
|
|
|
|
|
0
|
$Math::BSpline::Curve::logger->errorf("Fit failed"); |
99
|
0
|
|
|
|
|
0
|
return undef; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my $R = $class->_fit_calculate_R( |
103
|
|
|
|
|
|
|
$Nt, |
104
|
|
|
|
|
|
|
$args->{points}, |
105
|
3
|
|
|
|
|
29
|
); |
106
|
3
|
50
|
|
|
|
15
|
return undef if (!defined($R)); |
107
|
|
|
|
|
|
|
|
108
|
3
|
|
|
|
|
12
|
my $Pc = [map { $NtN->solve_LU($_) } @$R]; |
|
6
|
|
|
|
|
4249
|
|
109
|
|
|
|
|
|
|
my $P = $class->_fit_calculate_control_points( |
110
|
|
|
|
|
|
|
$Pc, |
111
|
|
|
|
|
|
|
$args->{vector_class}, |
112
|
3
|
|
|
|
|
3842
|
); |
113
|
3
|
50
|
|
|
|
14
|
return undef if (!defined($P)); |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
return { |
116
|
3
|
|
|
|
|
222
|
knot_vector => $U, |
117
|
|
|
|
|
|
|
control_points => $P, |
118
|
|
|
|
|
|
|
}; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _fit_calculate_lengths { |
123
|
2
|
|
|
2
|
|
5
|
my ($class, $points) = @_; |
124
|
|
|
|
|
|
|
|
125
|
2
|
|
|
|
|
4
|
my $lengths = []; |
126
|
2
|
|
|
|
|
4
|
my $total_length = 0; |
127
|
2
|
|
|
|
|
6
|
my $prv_point = $points->[0]; |
128
|
2
|
50
|
|
|
|
7
|
if (is_plain_arrayref($prv_point)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
129
|
2
|
|
|
|
|
4
|
my $dim = scalar(@$prv_point); |
130
|
2
|
|
|
|
|
8
|
for (my $i=1;$i<@$points;$i++) { |
131
|
398
|
|
|
|
|
606
|
my $cur_point = $points->[$i]; |
132
|
|
|
|
|
|
|
my $cur_dist = [ |
133
|
398
|
|
|
|
|
647
|
map { $cur_point->[$_] - $prv_point->[$_] } (0..($dim-1)), |
|
796
|
|
|
|
|
1599
|
|
134
|
|
|
|
|
|
|
]; |
135
|
|
|
|
|
|
|
my $cur_length = sqrt( |
136
|
|
|
|
|
|
|
sum0( |
137
|
398
|
|
|
|
|
715
|
map { $cur_dist->[$_]**2 } (0..($dim-1)), |
|
796
|
|
|
|
|
1703
|
|
138
|
|
|
|
|
|
|
), |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
|
141
|
398
|
|
|
|
|
761
|
push(@$lengths, $cur_length); |
142
|
398
|
|
|
|
|
568
|
$total_length += $cur_length; |
143
|
|
|
|
|
|
|
|
144
|
398
|
|
|
|
|
922
|
$prv_point = $cur_point; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
elsif ($prv_point->isa('Math::GSL::Vector')) { |
148
|
0
|
|
|
|
|
0
|
for (my $i=1;$i<@$points;$i++) { |
149
|
0
|
|
|
|
|
0
|
my $cur_point = $points->[$i]; |
150
|
0
|
|
|
|
|
0
|
my $cur_dist = $cur_point - $prv_point; |
151
|
0
|
|
|
|
|
0
|
my $cur_length = $cur_dist->norm(2); |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
push(@$lengths, $cur_length); |
154
|
0
|
|
|
|
|
0
|
$total_length += $cur_length; |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
0
|
$prv_point = $cur_point; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
elsif ($prv_point->isa('Math::MatrixReal')) { |
160
|
0
|
|
|
|
|
0
|
for (my $i=1;$i<@$points;$i++) { |
161
|
0
|
|
|
|
|
0
|
my $cur_point = $points->[$i]; |
162
|
0
|
|
|
|
|
0
|
my $cur_dist = $cur_point - $prv_point; |
163
|
0
|
|
|
|
|
0
|
my $cur_length = $cur_dist->norm_p(2); |
164
|
|
|
|
|
|
|
|
165
|
0
|
|
|
|
|
0
|
push(@$lengths, $cur_length); |
166
|
0
|
|
|
|
|
0
|
$total_length += $cur_length; |
167
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
0
|
$prv_point = $cur_point; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
elsif ($prv_point->isa('Math::Vector::Real')) { |
172
|
0
|
|
|
|
|
0
|
for (my $i=1;$i<@$points;$i++) { |
173
|
0
|
|
|
|
|
0
|
my $cur_point = $points->[$i]; |
174
|
0
|
|
|
|
|
0
|
my $cur_dist = $cur_point - $prv_point; |
175
|
0
|
|
|
|
|
0
|
my $cur_length = abs($cur_dist); |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
0
|
push(@$lengths, $cur_length); |
178
|
0
|
|
|
|
|
0
|
$total_length += $cur_length; |
179
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
0
|
$prv_point = $cur_point; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
elsif ($prv_point->isa('Math::VectorReal')) { |
184
|
0
|
|
|
|
|
0
|
for (my $i=1;$i<@$points;$i++) { |
185
|
0
|
|
|
|
|
0
|
my $cur_point = $points->[$i]; |
186
|
0
|
|
|
|
|
0
|
my $cur_dist = $cur_point - $prv_point; |
187
|
0
|
|
|
|
|
0
|
my $cur_length = $cur_dist->length; |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
0
|
push(@$lengths, $cur_length); |
190
|
0
|
|
|
|
|
0
|
$total_length += $cur_length; |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
$prv_point = $cur_point; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
else { |
196
|
|
|
|
|
|
|
# We assume that * is overloaded as dot product |
197
|
0
|
|
|
|
|
0
|
for (my $i=1;$i<@$points;$i++) { |
198
|
0
|
|
|
|
|
0
|
my $cur_point = $points->[$i]; |
199
|
0
|
|
|
|
|
0
|
my $cur_dist = $cur_point - $prv_point; |
200
|
0
|
|
|
|
|
0
|
my $cur_length = sqrt($cur_dist * $cur_dist); |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
0
|
push(@$lengths, $cur_length); |
203
|
0
|
|
|
|
|
0
|
$total_length += $cur_length; |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
0
|
$prv_point = $cur_point; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
2
|
|
|
|
|
8
|
return($lengths, $total_length); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub _fit_calculate_knot_vector { |
214
|
3
|
|
|
3
|
|
11
|
my ($class, $p, $n, $phi) = @_; |
215
|
3
|
|
|
|
|
8
|
my $m = @$phi + 1; |
216
|
|
|
|
|
|
|
|
217
|
3
|
|
|
|
|
9
|
my $U = [map { 0 } (0..$p)]; |
|
12
|
|
|
|
|
24
|
|
218
|
3
|
|
|
|
|
12
|
my $step = ($m + 1) / ($n - $p + 1); |
219
|
3
|
|
|
|
|
10
|
for (my $j=1;$j<=$n-$p;$j++) { |
220
|
108
|
|
|
|
|
186
|
my $i = int($j * $step); |
221
|
108
|
|
|
|
|
167
|
my $t = $j * $step - $i; |
222
|
108
|
|
|
|
|
268
|
push( |
223
|
|
|
|
|
|
|
@$U, |
224
|
|
|
|
|
|
|
(1 - $t) * $phi->[$i - 1] + $t * $phi->[$i], |
225
|
|
|
|
|
|
|
) |
226
|
|
|
|
|
|
|
} |
227
|
3
|
|
|
|
|
8
|
push(@$U, map { 1 } (0..$p)); |
|
12
|
|
|
|
|
21
|
|
228
|
|
|
|
|
|
|
|
229
|
3
|
|
|
|
|
12
|
return $U; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub _fit_calculate_Nt { |
234
|
3
|
|
|
3
|
|
11
|
my ($class, $basis, $phi) = @_; |
235
|
3
|
|
|
|
|
11
|
my $p = $basis->degree; |
236
|
3
|
|
|
|
|
62
|
my $U = $basis->knot_vector; |
237
|
3
|
|
|
|
|
30
|
my $n = (@$U - 1) - $p - 1; |
238
|
|
|
|
|
|
|
|
239
|
3
|
|
|
|
|
22
|
my $Nt = Math::Matrix::Banded->new( |
240
|
|
|
|
|
|
|
M => $n + 1, |
241
|
|
|
|
|
|
|
N => @$phi, |
242
|
|
|
|
|
|
|
); |
243
|
3
|
|
|
|
|
2218
|
for (my $j=0;$j<@$phi;$j++) { |
244
|
600
|
|
|
|
|
41396
|
my $u = $phi->[$j]; |
245
|
600
|
|
|
|
|
1668
|
my $s = $basis->find_knot_span($u); |
246
|
600
|
|
|
|
|
31449
|
my $Nip = $basis->evaluate_basis_functions($s, $u); |
247
|
600
|
|
|
|
|
51138
|
for (my $i=0;$i<@$Nip;$i++) { |
248
|
2400
|
|
|
|
|
226120
|
$Nt->element($s - $p + $i, $j, $Nip->[$i]); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
3
|
|
|
|
|
137
|
return $Nt; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _fit_calculate_R_plain_arrayref { |
257
|
3
|
|
|
3
|
|
9
|
my ($class, $Nt, $points) = @_; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# Because a plain arrayref does not overload scalar |
260
|
|
|
|
|
|
|
# multiplication we need to first split the array of points into |
261
|
|
|
|
|
|
|
# d (dimension of points) arrays of single numbers. |
262
|
3
|
|
|
|
|
7
|
my $dim = scalar(@{$points->[0]}); |
|
3
|
|
|
|
|
11
|
|
263
|
|
|
|
|
|
|
my $cmp_lists = [ |
264
|
3
|
|
|
|
|
12
|
map { [] } (1..$dim), |
|
6
|
|
|
|
|
19
|
|
265
|
|
|
|
|
|
|
]; |
266
|
3
|
|
|
|
|
16
|
for (my $i=0;$i<@$points;$i++) { |
267
|
600
|
|
|
|
|
917
|
my $v = $points->[$i]; |
268
|
600
|
|
|
|
|
1208
|
for (my $j=0;$j<$dim;$j++) { |
269
|
1200
|
|
|
|
|
1668
|
push(@{$cmp_lists->[$j]}, $v->[$j]); |
|
1200
|
|
|
|
|
3187
|
|
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
my $R_cmp_lists = [ |
274
|
3
|
|
|
|
|
10
|
map { $Nt->multiply_vector($_) } @$cmp_lists, |
|
6
|
|
|
|
|
8519
|
|
275
|
|
|
|
|
|
|
]; |
276
|
|
|
|
|
|
|
|
277
|
3
|
|
|
|
|
7914
|
my $R = []; |
278
|
3
|
|
|
|
|
11
|
for (my $i=0;$i<@{$R_cmp_lists->[0]};$i++) { |
|
123
|
|
|
|
|
258
|
|
279
|
120
|
|
|
|
|
208
|
my $components = [map { $R_cmp_lists->[$_]->[$i]} (0..($dim-1))]; |
|
240
|
|
|
|
|
484
|
|
280
|
120
|
|
|
|
|
291
|
for (my $l=0;$l<$dim;$l++) { |
281
|
240
|
|
100
|
|
|
457
|
$R->[$l] //= []; |
282
|
240
|
|
|
|
|
580
|
$R->[$l]->[$i] = $components->[$l]; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
3
|
|
|
|
|
44
|
return $R; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub _fit_calculate_R_math_gsl_vector { |
291
|
0
|
|
|
0
|
|
0
|
my ($class, $Nt, $points) = @_; |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# We can do the matrix multiplication for all dimensions in |
294
|
|
|
|
|
|
|
# one go because multiply_vector only does addition and scalar |
295
|
|
|
|
|
|
|
# multiplication, so if these are overloaded it can treat a |
296
|
|
|
|
|
|
|
# vector object just like a number. |
297
|
0
|
|
|
|
|
0
|
my $R_vec = $Nt->multiply_vector($points); |
298
|
0
|
|
|
|
|
0
|
my $R = []; |
299
|
0
|
|
|
|
|
0
|
for (my $i=0;$i<@$R_vec;$i++) { |
300
|
0
|
|
|
|
|
0
|
my $components = [$R_vec->[$i]->as_list]; |
301
|
0
|
|
|
|
|
0
|
for (my $l=0;$l<@$components;$l++) { |
302
|
0
|
|
0
|
|
|
0
|
$R->[$l] //= []; |
303
|
0
|
|
|
|
|
0
|
$R->[$l]->[$i] = $components->[$l]; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
0
|
return $R; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub _fit_calculate_R { |
312
|
3
|
|
|
3
|
|
14
|
my ($class, $Nt, $points) = @_; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# If the points are let's say 3-dimensional vectors, then we |
315
|
|
|
|
|
|
|
# want to return three array references with the x, y, and z |
316
|
|
|
|
|
|
|
# components of each point. |
317
|
|
|
|
|
|
|
|
318
|
3
|
|
|
|
|
10
|
my $v0 = $points->[0]; |
319
|
3
|
50
|
|
|
|
19
|
if (is_plain_arrayref($v0)) { |
|
|
0
|
|
|
|
|
|
320
|
3
|
|
|
|
|
18
|
return $class->_fit_calculate_R_plain_arrayref($Nt, $points); |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
elsif ($v0->isa('Math::GSL::Vector')) { |
323
|
0
|
|
|
|
|
0
|
return $class->_fit_calculate_R_math_gsl_vector($Nt, $points); |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
# elsif ($v0->isa('Math::MatrixReal')) { |
326
|
|
|
|
|
|
|
# return $class->_fit_calculate_R_math_matrixreal($Nt, $points); |
327
|
|
|
|
|
|
|
# } |
328
|
|
|
|
|
|
|
# elsif ($v0->isa('Math::Vector::Real')) { |
329
|
|
|
|
|
|
|
# return $class->_fit_calculate_R_math_vector_real($Nt, $points); |
330
|
|
|
|
|
|
|
# } |
331
|
|
|
|
|
|
|
# elsif ($v0->isa('Math::VectorReal')) { |
332
|
|
|
|
|
|
|
# return $class->_fit_calculate_R_math_vectorreal($Nt, $points); |
333
|
|
|
|
|
|
|
# } |
334
|
|
|
|
|
|
|
else { |
335
|
0
|
|
0
|
|
|
0
|
$Math::BSpline::Curve::logger->errorf( |
336
|
|
|
|
|
|
|
"Unsupported vector class: %s", |
337
|
|
|
|
|
|
|
blessed($v0) // 'undef', |
338
|
|
|
|
|
|
|
); |
339
|
0
|
|
|
|
|
0
|
return undef; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub _fit_calculate_control_points_plain_arrayref { |
345
|
3
|
|
|
3
|
|
9
|
my ($class, $Pc) = @_; |
346
|
|
|
|
|
|
|
|
347
|
3
|
|
|
|
|
9
|
my $P = []; |
348
|
3
|
|
|
|
|
11
|
for (my $i=0;$i<@{$Pc->[0]};$i++) { |
|
123
|
|
|
|
|
283
|
|
349
|
|
|
|
|
|
|
push( |
350
|
|
|
|
|
|
|
@$P, |
351
|
120
|
|
|
|
|
198
|
[map { $_->[$i] } @$Pc], |
|
240
|
|
|
|
|
485
|
|
352
|
|
|
|
|
|
|
); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
3
|
|
|
|
|
10
|
return $P; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub _fit_calculate_control_points_math_gsl_vector { |
360
|
0
|
|
|
0
|
|
0
|
my ($class, $Pc) = @_; |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
require_module('Math::GSL::Vector'); |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
0
|
my $P = []; |
365
|
0
|
|
|
|
|
0
|
for (my $i=0;$i<@{$Pc->[0]};$i++) { |
|
0
|
|
|
|
|
0
|
|
366
|
|
|
|
|
|
|
push( |
367
|
|
|
|
|
|
|
@$P, |
368
|
0
|
|
|
|
|
0
|
Math::GSL::Vector->new([map { $_->[$i] } @$Pc]), |
|
0
|
|
|
|
|
0
|
|
369
|
|
|
|
|
|
|
); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
0
|
|
|
|
|
0
|
return $P; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _fit_calculate_control_points_math_matrixreal { |
377
|
0
|
|
|
0
|
|
0
|
my ($class, $Pc) = @_; |
378
|
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
0
|
require_module('Math::MatrixReal'); |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
0
|
my $P = []; |
382
|
0
|
|
|
|
|
0
|
for (my $i=0;$i<@{$Pc->[0]};$i++) { |
|
0
|
|
|
|
|
0
|
|
383
|
|
|
|
|
|
|
push( |
384
|
|
|
|
|
|
|
@$P, |
385
|
|
|
|
|
|
|
Math::MatrixReal->new_from_cols( |
386
|
|
|
|
|
|
|
[ |
387
|
0
|
|
|
|
|
0
|
[map { $_->[$i] } @$Pc], |
|
0
|
|
|
|
|
0
|
|
388
|
|
|
|
|
|
|
], |
389
|
|
|
|
|
|
|
), |
390
|
|
|
|
|
|
|
); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
0
|
|
|
|
|
0
|
return $P; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub _fit_calculate_control_points { |
398
|
3
|
|
|
3
|
|
20
|
my ($class, $Pc, $vtc) = @_; |
399
|
|
|
|
|
|
|
|
400
|
3
|
50
|
|
|
|
13
|
if (!$vtc) { |
|
|
0
|
|
|
|
|
|
401
|
3
|
|
|
|
|
14
|
return $class->_fit_calculate_control_points_plain_arrayref($Pc); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
elsif ($vtc eq 'Math::GSL::Vector') { |
404
|
0
|
|
|
|
|
|
return $class->_fit_calculate_control_points_math_gsl_vector($Pc); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
# elsif ($vtc eq 'Math::MatrixReal') { |
407
|
|
|
|
|
|
|
# return $class->_fit_calculate_control_points_math_matrixreal($Pc); |
408
|
|
|
|
|
|
|
# } |
409
|
|
|
|
|
|
|
# elsif ($vtc eq 'Math::Vector::Real') { |
410
|
|
|
|
|
|
|
# return $class->_fit_calculate_control_points_math_vector_real($Pc); |
411
|
|
|
|
|
|
|
# } |
412
|
|
|
|
|
|
|
# elsif ($vtc eq 'Math::VectorReal') { |
413
|
|
|
|
|
|
|
# return $class->_fit_calculate_control_points_math_vectorreal($Pc); |
414
|
|
|
|
|
|
|
# } |
415
|
|
|
|
|
|
|
else { |
416
|
0
|
|
|
|
|
|
$Math::BSpline::Curve::logger->errorf( |
417
|
|
|
|
|
|
|
"Unsupported vector class: %s", |
418
|
|
|
|
|
|
|
$vtc, |
419
|
|
|
|
|
|
|
); |
420
|
0
|
|
|
|
|
|
return undef; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
1; |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
__END__ |