File Coverage

blib/lib/FigAnim/Spline.pm
Criterion Covered Total %
statement 12 409 2.9
branch 0 80 0.0
condition 0 27 0.0
subroutine 4 35 11.4
pod n/a
total 16 551 2.9


line stmt bran cond sub pod time code
1             package Spline;
2              
3             =head1 NAME
4              
5             Spline - A XFig file animator class - Spline object
6              
7             =head1 DESCRIPTION
8              
9             Spline object - object code in FIG format: 3.
10             Here are all the attributes of this class:
11              
12             B
13             area_fill, style_val, cap_style, forward_arrow, backward_arrow, npoints,
14             f_arrow_type, f_arrow_style, f_arrow_thickness, f_arrow_width, f_arrow_height,
15             b_arrow_type, b_arrow_style, b_arrow_thickness, b_arrow_width, b_arrow_height,
16             xnpoints, ynpoints, control_points, visibility, center_x, center_y,
17             max_spline_step, high_precision>
18              
19             =head1 FIG ATTRIBUTES
20              
21             =over
22              
23             =item sub_type
24              
25             0: opened approximated spline;
26             1: closed approximated spline;
27             2: opened interpolated spline;
28             3: closed interpolated spline;
29             4: opened x-spline;
30             5: closed x-spline.
31              
32             =item line_style
33              
34             -1: Default;
35             0: Solid;
36             1: Dashed;
37             2: Dotted;
38             3: Dash-dotted;
39             4: Dash-double-dotted;
40             5: Dash-triple-dotted.
41              
42             =item thickness
43              
44             80-ths of an inch ("display units")
45              
46             =item pen_color
47              
48             -1..31: FIG colors;
49             32..543 (512 total): user colors.
50              
51             =item fill_color
52              
53             -1..31: FIG colors;
54             32..543 (512 total): user colors.
55              
56             =item depth
57              
58             0 ... 999: larger value means object is deeper than (under)
59             objects with smaller depth
60              
61             =item pen_style
62              
63             unused
64              
65             =item area_fill
66              
67             fill type
68              
69             =item style_val
70              
71             length, in 1/80 inches, of the on/off
72             dashes for dashed lines, and the distance between the dots, in 1/80 inches,
73             for dotted lines
74              
75             =item cap_style
76              
77             0 = Butt (default);
78             1 = Round;
79             2 = Projecting.
80              
81             =item forward_arrow
82              
83             0: no forward arrow;
84             1: on
85              
86             =item backward_arrow
87              
88             0: no backward arrow;
89             1: on
90              
91             =item npoints
92              
93             number of control points in spline
94              
95             =item f_arrow_type, b_arrow_type
96              
97             0: Stick-type (default);
98             1: Closed triangle;
99             2: Closed with "indented" butt;
100             3: Closed with "pointed" butt
101              
102             =item f_arrow_style, b_arrow_style
103              
104             0: Hollow (filled with white);
105             1: Filled with pen_color
106              
107             =item f_arrow_thickness, b_arrow_thickness
108              
109             1/80 inch
110              
111             =item f_arrow_width, b_arrow_width
112              
113             Fig units
114              
115             =item f_arrow_height, b_arrow_height
116              
117             Fig units
118              
119             =item xnpoints, ynpoints
120              
121             arrays of points coordinates in Fig units
122              
123             =item control_points
124              
125             array of control points values:
126             there is one shape factor for each point. The value of this factor
127             must be between -1 (which means that the spline is interpolated at
128             this point) and 1 (which means that the spline is approximated at
129             this point). The spline is always smooth in the neighbourhood of a
130             control point, except when the value of the factor is 0 for which
131             there is a first-order discontinuity (i.e. angular point).
132              
133             =back
134              
135             =head1 ADDITONNAL ATTRIBUTES
136              
137             =over
138              
139             =item visibility
140              
141             0: hidden;
142             1: shown
143              
144             =item center_x, center_y
145              
146             calculated center (Fig units)
147              
148             =item max_spline_step
149              
150             parameter for computing polyline from spline (default 0.2)
151              
152             =item high_precision
153              
154             parameter for computing polyline from spline (default 0.5)
155              
156             =back
157              
158             =cut
159              
160 1     1   5 use strict;
  1         2  
  1         36  
161 1     1   7 use warnings;
  1         1  
  1         29  
162              
163             # useful classes
164 1     1   7 use FigAnim::Utils;
  1         2  
  1         19  
165 1     1   570 use FigAnim::Point;
  1         3  
  1         5010  
166              
167             # constructor
168             sub new {
169 0     0     my $proto = shift;
170 0   0       my $class = ref($proto) || $proto;
171 0           my $self = {};
172            
173 0           $self->{name} = shift; # object's name in comment
174            
175             #$self->{object_code} = 3;
176 0           $self->{sub_type} = shift;
177 0           $self->{line_style} = shift;
178 0           $self->{thickness} = shift;
179 0           $self->{pen_color} = shift;
180 0           $self->{fill_color} = shift;
181 0           $self->{depth} = shift;
182 0           $self->{pen_style} = shift;
183 0           $self->{area_fill} = shift;
184 0           $self->{style_val} = shift;
185 0           $self->{cap_style} = shift;
186 0           $self->{forward_arrow} = shift;
187 0           $self->{backward_arrow} = shift;
188 0           $self->{npoints} = shift;
189            
190             # forward arrow
191 0           $self->{f_arrow_type} = shift;
192 0           $self->{f_arrow_style} = shift;
193 0           $self->{f_arrow_thickness} = shift;
194 0           $self->{f_arrow_width} = shift;
195 0           $self->{f_arrow_height} = shift;
196            
197             # backward arrow
198 0           $self->{b_arrow_type} = shift;
199 0           $self->{b_arrow_style} = shift;
200 0           $self->{b_arrow_thickness} = shift;
201 0           $self->{b_arrow_width} = shift;
202 0           $self->{b_arrow_height} = shift;
203            
204             # points
205 0           $self->{xnpoints} = shift;
206 0           $self->{ynpoints} = shift;
207 0           $self->{points} = [];
208              
209             # control points
210 0           $self->{control_points} = shift;
211            
212             # reference to the FigFile
213 0           $self->{fig_file} = shift;
214            
215             # object's visibility : 0=hidden 1=shown
216 0           $self->{visibility} = 1;
217            
218             # calculated center
219 0           $self->{center_x} = undef;
220 0           $self->{center_y} = undef;
221              
222             # computed polyline from spline
223 0           $self->{x} = []; # computed x points
224 0           $self->{y} = []; # computed y points
225 0           $self->{n} = 0; # number of computed points
226              
227             # parameters for computing splines
228 0           $self->{max_spline_step} = 0.2;
229 0           $self->{high_precision} = 0.5;
230              
231             # animations
232 0           $self->{animations} = [];
233              
234 0           bless ($self, $class);
235 0           return $self;
236             }
237              
238              
239             # methods
240             sub clone {
241 0     0     my $self = shift;
242 0           my $obj = new Spline;
243              
244 0           foreach ('name','sub_type','line_style','thickness','pen_color',
245             'fill_color','depth','pen_style','area_fill','style_val',
246             'cap_style','forward_arrow','backward_arrow','npoints',
247             'f_arrow_type','f_arrow_style','f_arrow_thickness',
248             'f_arrow_width','f_arrow_height','b_arrow_type','b_arrow_style',
249             'b_arrow_thickness','b_arrow_width','b_arrow_height','fig_file',
250             'visibility','center_x','center_y') {
251 0           $obj->{$_} = $self->{$_};
252             }
253              
254 0           $obj->{xnpoints} = [];
255 0           push @{$obj->{xnpoints}}, @{$self->{xnpoints}};
  0            
  0            
256              
257 0           $obj->{ynpoints} = [];
258 0           push @{$obj->{ynpoints}}, @{$self->{ynpoints}};
  0            
  0            
259              
260 0           $obj->{control_points} = [];
261 0           push @{$obj->{control_points}}, @{$self->{control_points}};
  0            
  0            
262              
263 0           return $obj;
264             }
265              
266             sub output {
267 0     0     my $self = shift;
268 0 0         return if ($self->{visibility} == 0);
269            
270 0           my $fh = shift;
271            
272 0           foreach (split(/\n/, $self->{name})) {
273 0           printf $fh "# $_\n";
274             }
275            
276 0           printf $fh
277             "3 %d %d %d %d %d %d %d %d %.3f %d %d %d %d\n",
278             @$self{'sub_type','line_style','thickness','pen_color','fill_color',
279             'depth','pen_style','area_fill','style_val','cap_style',
280             'forward_arrow','backward_arrow','npoints'};
281            
282 0 0         if ($self->{forward_arrow}) {
283 0           printf $fh "\t%d %d %.2f %.2f %.2f\n",
284             @$self{'f_arrow_type','f_arrow_style','f_arrow_thickness',
285             'f_arrow_width','f_arrow_height'};
286             }
287            
288 0 0         if ($self->{backward_arrow}) {
289 0           printf $fh "\t%d %d %.2f %.2f %.2f\n",
290             @$self{'b_arrow_type','b_arrow_style','b_arrow_thickness',
291             'b_arrow_width','b_arrow_height'};
292             }
293            
294 0           for (0..$self->{npoints}-1) {
295 0 0         printf $fh "\t" if (($_ % 6) == 0);
296 0           printf $fh " %d %d", $self->{xnpoints}[$_], $self->{ynpoints}[$_];
297 0 0         printf $fh "\n" if (($_ % 6) == 5);
298             }
299 0 0         printf $fh "\n" if (($self->{npoints} % 6) != 0);
300            
301 0           for (0..$self->{npoints}-1) {
302 0 0         printf $fh "\t" if (($_ % 8) == 0);
303 0           printf $fh " %.3f", $self->{control_points}[$_];
304 0 0         printf $fh "\n" if (($_ % 8) == 7);
305             }
306 0 0         printf $fh "\n" if (($self->{npoints} % 8) != 0);
307             }
308              
309             sub calculateCenter {
310 0     0     my $self = shift;
311 0 0 0       if (($self->{npoints} > 1) &&
      0        
312             ($self->{xnpoints}[$self->{npoints}-1] == $self->{xnpoints}[0]) &&
313             ($self->{ynpoints}[$self->{npoints}-1] == $self->{ynpoints}[0])) {
314 0           $self->{center_x} =
315             sprintf("%.0f",
316             eval(join('+',
317 0           @{$self->{xnpoints}}[0..$self->{npoints}-2]
318             )
319             ) / ($self->{npoints}-1));
320 0           $self->{center_y} =
321             sprintf("%.0f",
322             eval(join('+',
323 0           @{$self->{ynpoints}}[0..$self->{npoints}-2]
324             )
325             ) / ($self->{npoints}-1));
326             } else {
327 0           $self->{center_x} =
328             sprintf("%.0f",
329 0           eval(join('+',@{$self->{xnpoints}}))/$self->{npoints});
330 0           $self->{center_y} =
331             sprintf("%.0f",
332 0           eval(join('+',@{$self->{ynpoints}}))/$self->{npoints});
333             }
334             }
335              
336              
337             # animation methods
338             sub setAttributeValue {
339 0     0     my $self = shift;
340 0           my @anim = (0, $self->{name}, shift, 0, shift, shift);
341 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
342             }
343              
344             sub setPenColor {
345 0     0     my $self = shift;
346 0           my $time = shift;
347 0           my $color = shift;
348 0           my $code = $FigAnim::Utils::colors_codes{$color};
349 0 0         if (defined $color) {
350 0           my @anim = (0, $self->{name}, $time, 0, 'pen_color', $code);
351 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
352             }
353             }
354              
355             sub setFillColor {
356 0     0     my $self = shift;
357 0           my $time = shift;
358 0           my $color = shift;
359 0           my $code = $FigAnim::Utils::colors_codes{$color};
360 0 0         if (defined $color) {
361 0           my @anim = (0, $self->{name}, $time, 0, 'fill_color', $code);
362 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
363             }
364             }
365              
366             sub hide {
367 0     0     my $self = shift;
368 0           my @anim = (0, $self->{name}, shift, 0, 'visibility', 0);
369 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
370             }
371              
372             sub show {
373 0     0     my $self = shift;
374 0           my @anim = (0, $self->{name}, shift, 0, 'visibility', 1);
375 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
376             }
377              
378             sub changeThickness {
379 0     0     my $self = shift;
380 0           my @anim = (1, $self->{name}, shift, shift, int shift);
381 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
382             }
383              
384             sub changeFillIntensity {
385 0     0     my $self = shift;
386 0           my @anim = (2, $self->{name}, shift, shift, int shift);
387 0 0         $anim[4] = 0 if ($anim[4] < 0);
388 0 0         $anim[4] = 20 if ($anim[4] > 20);
389 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
390             }
391              
392             sub translate {
393 0     0     my $self = shift;
394 0           my @anim = (13, $self->{name}, shift, shift, shift, shift, shift);
395 0 0         $anim[6] = '' if (!(defined $anim[6]));
396 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
397             }
398              
399             sub rotate {
400 0     0     my $self = shift;
401 0           my @anim = (23, $self->{name}, shift, shift, shift, shift, shift, shift);
402 0 0 0       if (!((defined $anim[5]) && (defined $anim[6]))) {
403 0           $anim[5] = $self->{center_x};
404 0           $anim[6] = $self->{center_y};
405             }
406 0 0         $anim[7] = '' if (!(defined $anim[7]));
407 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
408             }
409              
410             sub scale {
411 0     0     my $self = shift;
412 0           my @anim = (33, $self->{name}, shift, shift, shift, shift, shift);
413 0 0 0       if (!((defined $anim[5]) && (defined $anim[6]))) {
414 0           $anim[5] = $self->{center_x};
415 0           $anim[6] = $self->{center_y};
416             }
417 0           push @{$self->{fig_file}->{animations}}, \@anim;
  0            
418             }
419              
420              
421             # outputs a SVG element
422             sub outputSVG {
423 0     0     my $self = shift;
424 0           my $fh = shift;
425              
426 0           my ($colors) = @_;
427              
428 0           foreach (split(/\n/, $self->{name})) {
429 0           print $fh "\n";
430             }
431            
432             # converts values in SVG-CSS
433              
434             # points
435 0           for (0 .. $self->{npoints}-1) {
436 0           push @{$self->{points}}, new Point($self->{xnpoints}[$_],
  0            
437             $self->{ynpoints}[$_]);
438             }
439              
440 0 0         if ($self->{sub_type} % 2 == 0) {
441 0           $self->compute_open_spline($self->{high_precision});
442             } else {
443 0           $self->compute_closed_spline($self->{high_precision});
444             }
445 0           my $points = "points=\"";
446 0           for (0 .. $self->{n}-1) {
447 0           $points .= $self->{x}[$_] . " " . $self->{y}[$_];
448 0 0         $points .= ", " if ($_ < $self->{n}-1);
449             }
450 0           $points .= "\"";
451              
452             # style
453 0           my $style = "style=\"";
454              
455             # converts arrows into SVG paths
456             # - too much bugs
457              
458              
459             # line_style, style_val, pen_color
460 0           $style .= ConvertSVG::line_style_to_stroke($self->{line_style},
461             $self->{style_val},
462             $self->{pen_color},
463             $colors) . "; ";
464             # thickness
465 0           $style .= ConvertSVG::thickness_to_stroke($self->{thickness}) . "; ";
466              
467             # fill_color, area_fill
468 0           $style .= ConvertSVG::area_fill_to_fill($self->{area_fill},
469             $self->{fill_color},
470             $colors) . "; ";
471              
472             # cap_style
473 0           $style .= ConvertSVG::cap_style_to_linecap($self->{cap_style}) . "; ";
474              
475             # end of style
476 0           $style .= "\"";
477              
478 0           print $fh "
479              
480 0 0         if ($#{$self->{animations}} >= 0) { # SVG + SMIL
  0            
481 0           print $fh ">\n";
482 0           for (my $i = 0; $i <= $#{$self->{animations}}; $i++) {
  0            
483 0           print $fh "\t";
484 0           my $smil = ConvertSMIL::smil($self->{animations}[$i]);
485 0           print $fh $smil;
486 0           print $fh "\n";
487             }
488 0           print $fh "\n\n";
489             } else { # SVG only
490 0           print $fh " />\n\n";
491             }
492             }
493              
494              
495             # curves for X-splines
496             # the following spline drawing routines are from:
497             # "X-splines : A Spline Model Designed for the End User"
498             # by Carole BLANC and Christophe SCHLICK, Proceedings of SIGGRAPH'95
499             # and "trans_spline.c" from "fig2dev" sources
500              
501             sub round {
502 0     0     my ($number) = shift;
503 0           return int($number + .5);
504             }
505              
506             sub add_point {
507 0     0     my $self = shift;
508              
509 0           my ($i, $j) = @_;
510              
511 0 0 0       if (($self->{n} > 0) &&
      0        
512             ($i == $self->{x}[$self->{n}-1]) &&
513             ($j == $self->{y}[$self->{n}-1])) {
514             } else {
515 0           push @{$self->{x}}, $i;
  0            
516 0           push @{$self->{y}}, $j;
  0            
517 0           $self->{n}++;
518             }
519             }
520              
521             sub compute_open_spline {
522 0     0     my $self = shift;
523              
524 0           my ($precision) = @_;
525              
526 0           my $k;
527             my $step;
528 0           my ($p0, $p1, $p2, $p3);
529 0           my ($s0, $s1, $s2, $s3);
530              
531             # special case - two point spline is just straight line
532 0 0         if ($self->{npoints} == 2) {
533 0           $self->add_point($self->{points}[0]->{x},$self->{points}[0]->{y});
534 0           $self->add_point($self->{points}[1]->{x},$self->{points}[1]->{y});
535 0           return;
536             }
537              
538 0           $p0 = $self->{points}[0]; $s0 = $self->{control_points}[0];
  0            
539 0           $p1 = $p0; $s1 = $s0;
  0            
540             # first control point is needed twice for the first segment
541 0           $p2 = $self->{points}[1]; $s2 = $self->{control_points}[1];
  0            
542              
543 0 0         if ($self->{npoints} == 2) {
544 0           $p3 = $p2; $s3 = $s2;
  0            
545             } else {
546 0           $p3 = $self->{points}[2]; $s3 = $self->{control_points}[2];
  0            
547             }
548              
549 0           OPEN_SPLINE: for ($k = 0; ; $k++) {
550 0           $step = $self->step_computing($k,
551             $p0, $p1, $p2, $p3,
552             $s1, $s2, $precision);
553 0           $self->spline_segment_computing($step, $k,
554             $p0, $p1, $p2, $p3, $s1, $s2);
555              
556 0 0         last OPEN_SPLINE if ($k >= $self->{npoints}-3);
557              
558 0           $p0 = $p1; $s0 = $s1;
  0            
559 0           $p1 = $p2; $s1 = $s2;
  0            
560 0           $p2 = $p3; $s2 = $s3;
  0            
561 0           $p3 = $self->{points}[$k+3]; $s3 = $self->{control_points}[$k+3];
  0            
562             }
563              
564             # last control point is needed twice for the last segment
565 0           $p0 = $p1; $s0 = $s1;
  0            
566 0           $p1 = $p2; $s1 = $s2;
  0            
567 0           $p2 = $p3; $s2 = $s3;
  0            
568              
569 0           $step = $self->step_computing($k,
570             $p0, $p1, $p2, $p3,
571             $s1, $s2, $precision);
572 0           $self->spline_segment_computing($step, $k,
573             $p0, $p1, $p2, $p3, $s1, $s2);
574              
575 0           $self->add_point($p3->{x}, $p3->{y});
576             }
577              
578             sub compute_closed_spline {
579 0     0     my $self = shift;
580              
581 0           my ($precision) = @_;
582              
583 0           my ($k, $i);
584 0           my $step;
585 0           my ($p0, $p1, $p2, $p3, $first);
586 0           my ($s0, $s1, $s2, $s3, $s_first);
587              
588 0           $p0 = $self->{points}[0]; $s0 = $self->{control_points}[0];
  0            
589 0           $p1 = $self->{points}[1]; $s1 = $self->{control_points}[1];
  0            
590 0           $p2 = $self->{points}[2]; $s2 = $self->{control_points}[2];
  0            
591 0           $p3 = $self->{points}[3]; $s3 = $self->{control_points}[3];
  0            
592              
593 0           $first = $p0; $s_first = $s0;
  0            
594              
595 0           for ($k = 0; $k < $self->{npoints}-3; $k++) {
596             # probleme ici
597 0           $step = $self->step_computing($k,
598             $p0, $p1, $p2, $p3,
599             $s1, $s2, $precision);
600             # ok
601 0           $self->spline_segment_computing($step, $k,
602             $p0, $p1, $p2, $p3, $s1, $s2);
603 0           $p0 = $p1; $s0 = $s1;
  0            
604 0           $p1 = $p2; $s1 = $s2;
  0            
605 0           $p2 = $p3; $s2 = $s3;
  0            
606 0           $p3 = $self->{points}[$k+4]; $s3 = $self->{control_points}[$k+4];
  0            
607             }
608              
609             # when we are at the end, join to the beginning
610 0           $p3 = $first; $s3 = $s_first;
  0            
611              
612 0           $step = $self->step_computing($k,
613             $p0, $p1, $p2, $p3, $s1, $s2, $precision);
614 0           $self->spline_segment_computing($step, $k, $p0, $p1, $p2, $p3, $s1, $s2);
615              
616 0           for ($i = 0; $i < 2; $i++) {
617 0           $k++;
618              
619 0           $p0 = $p1; $s0 = $s1;
  0            
620 0           $p1 = $p2; $s1 = $s2;
  0            
621 0           $p2 = $p3; $s2 = $s3;
  0            
622 0           $p3 = $self->{points}[$i+1]; $s3 = $self->{control_points}[$i+1];
  0            
623              
624 0           $step = $self->step_computing($k,
625             $p0, $p1, $p2, $p3,
626             $s1, $s2, $precision);
627 0           $self->spline_segment_computing($step, $k,
628             $p0, $p1, $p2, $p3, $s1, $s2);
629             }
630              
631 0           $self->add_point($self->{x}[0], $self->{y}[0]);
632             }
633              
634             sub Q {
635 0     0     my ($d) = @_;
636 0           return -1.0 * $d;
637             }
638              
639             sub f_blend {
640 0     0     my ($numerator, $denominator) = @_;
641              
642 0           my $p = 2.0 * $denominator * $denominator;
643 0           my $u = $numerator / $denominator;
644 0           my $u2 = $u * $u;
645              
646 0           return ($u * $u2 * (10.0 - $p + (2.0*$p - 15.0)*$u + (6.0 - $p)*$u2));
647             }
648              
649             sub g_blend {
650 0     0     my ($u, $q) = @_;
651              
652             return
653 0           ($u*($q +
654             $u*(2.0*$q +
655             $u*(8.0 - 12.0*$q +
656             $u*(14.0*$q - 11.0 +
657             $u*(4.0 - 5.0*$q))))));
658             }
659              
660             sub h_blend {
661 0     0     my ($u, $q) = @_;
662              
663 0           my $u2 = $u * $u;
664             return
665 0           ($u * ($q + $u * (2.0 * $q + $u2 * (-2.0*$q - $u*$q))));
666             }
667              
668             sub negative_s1_influence {
669 0     0     my ($t, $s1, $A0, $A2) = @_;
670              
671 0           $$A0 = h_blend(-$t, Q($s1));
672 0           $$A2 = g_blend($t, Q($s1));
673             }
674              
675             sub negative_s2_influence {
676 0     0     my ($t, $s2, $A1, $A3) = @_;
677              
678 0           $$A1 = g_blend(1-$t, Q($s2));
679 0           $$A3 = h_blend($t-1, Q($s2));
680             }
681              
682             sub positive_s1_influence {
683 0     0     my ($k, $t, $s1, $A0, $A2) = @_;
684              
685 0           my $Tk;
686              
687 0           $Tk = $k+1.0+$s1;
688 0 0         $$A0 = ($t+$k+1.0<$Tk) ? f_blend($t+$k+1.0-$Tk, $k-$Tk) : 0.0;
689              
690 0           $Tk = $k+1.0-$s1;
691 0           $$A2 = f_blend($t+$k+1.0-$Tk, $k+2.0-$Tk);
692             }
693              
694             sub positive_s2_influence {
695 0     0     my ($k, $t, $s2, $A1, $A3) = @_;
696              
697 0           my $Tk;
698              
699 0           $Tk = $k+2.0+$s2;
700 0           $$A1 = f_blend($t+$k+1-$Tk, $k+1-$Tk);
701              
702 0           $Tk = $k+2.0-$s2;
703 0 0         $$A3 = ($t+$k+1.0>$Tk) ? f_blend($t+$k+1.0-$Tk, $k+3.0-$Tk) : 0.0;
704             }
705              
706             sub point_adding {
707 0     0     my $self = shift;
708              
709 0           my ($A_blend, $p0, $p1, $p2, $p3) = @_;
710              
711 0           my $weights_sum =
712             @$A_blend[0] + @$A_blend[1] + @$A_blend[2] + @$A_blend[3];
713              
714 0           my $x_sum = @$A_blend[0]*$p0->{x} + @$A_blend[1]*$p1->{x} +
715             @$A_blend[2]*$p2->{x} + @$A_blend[3]*$p3->{x};
716              
717 0           my $y_sum = @$A_blend[0]*$p0->{y} + @$A_blend[1]*$p1->{y} +
718             @$A_blend[2]*$p2->{y} + @$A_blend[3]*$p3->{y};
719              
720 0           $self->add_point(round($x_sum / $weights_sum),
721             round($y_sum / $weights_sum));
722             }
723              
724             sub point_computing {
725 0     0     my $self = shift;
726              
727 0           my ($A_blend, $p0, $p1, $p2, $p3, $x, $y) = @_;
728              
729 0           my $weights_sum =
730             @$A_blend[0] + @$A_blend[1] + @$A_blend[2] + @$A_blend[3];
731              
732 0           my $x_sum = @$A_blend[0]*$p0->{x} + @$A_blend[1]*$p1->{x} +
733             @$A_blend[2]*$p2->{x} + @$A_blend[3]*$p3->{x};
734              
735 0           my $y_sum = @$A_blend[0]*$p0->{y} + @$A_blend[1]*$p1->{y} +
736             @$A_blend[2]*$p2->{y} + @$A_blend[3]*$p3->{y};
737              
738 0           $$x = round($x_sum / $weights_sum);
739 0           $$y = round($y_sum / $weights_sum);
740             }
741              
742             sub step_computing {
743 0     0     my $self = shift;
744              
745 0           my ($k, $p0, $p1, $p2, $p3, $s1, $s2, $precision) = @_;
746              
747 0           my @A_blend = [0.0, 0.0, 0.0, 0.0];
748 0           my ($xstart, $ystart, $xend, $yend, $xmid, $ymid, $xlength, $ylength);
749 0           my ($start_to_end_dist, $number_of_steps);
750 0           my ($step, $angle_cos, $scal_prod,
751             $xv1, $xv2, $yv1, $yv2,
752             $sides_length_prod);
753              
754             # origin
755 0 0         if ($s1 > 0.0) {
756 0 0         if ($s2 < 0.0) {
757 0           positive_s1_influence($k, 0.0, $s1, \$A_blend[0], \$A_blend[2]);
758 0           negative_s2_influence(0.0, $s2, \$A_blend[1], \$A_blend[3]);
759             } else {
760 0           positive_s1_influence($k, 0.0, $s1, \$A_blend[0], \$A_blend[2]);
761 0           positive_s2_influence($k, 0.0, $s2, \$A_blend[1], \$A_blend[3]);
762             }
763 0           $self->point_computing(\@A_blend, $p0, $p1, $p2, $p3,
764             \$xstart, \$ystart);
765             } else {
766 0           $xstart = $p1->{x};
767 0           $ystart = $p1->{y};
768             }
769              
770             # extremity
771 0 0         if ($s2 > 0.0) {
772 0 0         if ($s1 < 0) {
773 0           negative_s1_influence(1.0, $s1, \$A_blend[0], \$A_blend[2]);
774 0           positive_s2_influence($k, 1.0, $s2, \$A_blend[1], \$A_blend[3]);
775             } else {
776 0           positive_s1_influence($k, 1.0, $s1, \$A_blend[0], \$A_blend[2]);
777 0           positive_s2_influence($k, 1.0, $s2, \$A_blend[1], \$A_blend[3]);
778             }
779 0           $self->point_computing(\@A_blend, $p0, $p1, $p2, $p3,
780             \$xend, \$yend);
781             } else {
782 0           $xend = $p2->{x};
783 0           $yend = $p2->{y};
784             }
785              
786             # middle
787 0 0         if ($s2 > 0.0) {
    0          
788 0 0         if ($s1 < 0.0) {
789 0           negative_s1_influence(0.5, $s1, \$A_blend[0], \$A_blend[2]);
790 0           positive_s2_influence($k, 0.5, $s2, \$A_blend[1], \$A_blend[3]);
791             } else {
792 0           positive_s1_influence($k, 0.5, $s1, \$A_blend[0], \$A_blend[2]);
793 0           positive_s2_influence($k, 0.5, $s2, \$A_blend[1], \$A_blend[3]);
794             }
795             } elsif ($s1 < 0.0) {
796 0           negative_s1_influence(0.5, $s1, \$A_blend[0], \$A_blend[2]);
797 0           negative_s2_influence(0.5, $s2, \$A_blend[1], \$A_blend[3]);
798             } else {
799 0           positive_s1_influence($k, 0.5, $s1, \$A_blend[0], \$A_blend[2]);
800 0           negative_s2_influence(0.5, $s2, \$A_blend[1], \$A_blend[3]);
801             }
802              
803 0           $self->point_computing(\@A_blend, $p0, $p1, $p2, $p3, \$xmid, \$ymid);
804              
805 0           $xv1 = $xstart - $xmid;
806 0           $yv1 = $ystart - $ymid;
807 0           $xv2 = $xend - $xmid;
808 0           $yv2 = $yend - $ymid;
809              
810 0           $scal_prod = $xv1*$xv2 + $yv1*$yv2;
811              
812 0           $sides_length_prod = sqrt(($xv1*$xv1 + $yv1*$yv1)*($xv2*$xv2 + $yv2*$yv2));
813              
814             # cosinus of origin-middle-extremity angle
815 0 0         if ($sides_length_prod == 0.0) {
816 0           $angle_cos = 0.0;
817             } else {
818 0           $angle_cos = $scal_prod/$sides_length_prod;
819             }
820              
821 0           $xlength = $xend - $xstart;
822 0           $ylength = $yend - $ystart;
823              
824 0           $start_to_end_dist = int(sqrt($xlength*$xlength + $ylength*$ylength));
825              
826             # more steps if segment's origin and extremity are remote
827 0           $number_of_steps = int(sqrt($start_to_end_dist)/2);
828              
829             # more steps if the curve is high
830 0           $number_of_steps += int(((1.0 + $angle_cos)*10.0));
831              
832 0 0 0       if (($number_of_steps == 0) || ($number_of_steps > 999)) {
833 0           $step = 1.0;
834             } else {
835 0           $step = $precision/$number_of_steps;
836             }
837              
838 0 0 0       if (($step > $self->{max_spline_step}) || ($step == 0)) {
839 0           $step = $self->{max_spline_step};
840             }
841              
842 0           return $step;
843             }
844              
845             sub spline_segment_computing {
846 0     0     my $self = shift;
847              
848 0           my ($step, $k, $p0, $p1, $p2, $p3, $s1, $s2) = @_;
849              
850 0           my @A_blend = [0.0, 0.0, 0.0, 0.0];
851 0           my $t;
852              
853 0 0         if ($s1 < 0.0) {
    0          
854 0 0         if ($s2 < 0.0) {
855 0           for ($t = 0.0; $t < 1.0; $t += $step) {
856 0           negative_s1_influence($t, $s1, \$A_blend[0], \$A_blend[2]);
857 0           negative_s2_influence($t, $s2, \$A_blend[1], \$A_blend[3]);
858              
859 0           $self->point_adding(\@A_blend, $p0, $p1, $p2, $p3);
860             }
861             } else {
862 0           for ($t = 0.0; $t < 1.0; $t += $step) {
863 0           negative_s1_influence($t, $s1, \$A_blend[0], \$A_blend[2]);
864 0           positive_s2_influence($k, $t, $s2, \$A_blend[1], \$A_blend[3]);
865              
866 0           $self->point_adding(\@A_blend, $p0, $p1, $p2, $p3);
867             }
868             }
869             } elsif ($s2 < 0.0) {
870 0           for ($t = 0.0; $t < 1.0; $t += $step) {
871 0           positive_s1_influence($k, $t, $s1, \$A_blend[0], \$A_blend[2]);
872 0           negative_s2_influence($t, $s2, \$A_blend[1], \$A_blend[3]);
873              
874 0           $self->point_adding(\@A_blend, $p0, $p1, $p2, $p3);
875             }
876             } else {
877 0           for ($t = 0.0; $t < 1.0; $t += $step) {
878 0           positive_s1_influence($k, $t, $s1, \$A_blend[0], \$A_blend[2]);
879 0           positive_s2_influence($k, $t, $s2, \$A_blend[1], \$A_blend[3]);
880              
881 0           $self->point_adding(\@A_blend, $p0, $p1, $p2, $p3);
882             }
883             }
884             }
885              
886              
887              
888             1;