File Coverage

blib/lib/LaTeX/PGF/Diagram2D/Plot.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1              
2             package LaTeX::PGF::Diagram2D::Plot;
3              
4 1     1   20 use 5.000000;
  1         4  
  1         41  
5 1     1   5 use strict;
  1         3  
  1         30  
6 1     1   14 use warnings;
  1         2  
  1         23  
7              
8 1     1   4 use Carp;
  1         2  
  1         127  
9              
10             our @ISA = qw();
11              
12             our $VERSION = '1.00';
13              
14             require LaTeX::PGF::Diagram2D::Xspline;
15              
16             # Plot types, Output (t):
17             # 0 Dots
18             # 1 Curve
19             # 2 Lines
20              
21             # Plot data types, input (d):
22             # 0 Function, optionally with derivative given
23             # d1=function, d2=derivative
24             # 1 Points (optionally with a derivative)
25             # d1=reference to array of points
26             # 2 Parametric function
27             # d1=xfunction d2=yfunction, d3=xderivative (opt), d4=yderivative (opt)
28             # 3 X-spline points (open spline)
29              
30              
31              
32              
33             # Dot style:
34             # 0 = circle
35             # 1 = square
36             # 2 = diamond
37             # 3 = triangle
38             # 4 = crosshair
39             # 5 = pentagon
40              
41              
42 1     1   499 use PDL;
  0            
  0            
43              
44              
45              
46             sub new
47             {
48             my $self = undef;
49             if($#_ < 0) {
50             croak "Usage: LaTeX::PGF::Diagram2D::Plot->new()";
51             } else {
52             my $class = shift;
53             $self = {
54             't' => 1, # Plot type: -1=unknown, 0=points, 1=curve, 2=lines
55             'd' => -1, # Data type: -1=unknown, 0=function, 1=points, 2=param
56             'r' => undef, # Range (for undef use entire x-axis or plot points)
57             'd1' => undef, # Data 1 (Function or array of points)
58             'd2' => undef, # Data 2 (Derivative function)
59             'd3' => undef, # Data 3
60             'd4' => undef, # Data 4
61             'f' => undef, # Flag: Finished.
62             'ax' => undef, # x axis
63             'ay' => undef, # y axis
64             'color' => undef, # Plot color
65             'pp' => undef, # Paper points (userspace coordinates)
66             'i' => 20, # Number of curve intervals
67             'ds' => 0, # Dot style
68             'dsz' => 5.0, # Dot size (diameter, multiple of line size)
69             'debug' => 0, # Flag: Debug
70             'xspline' => 8, # Bezier segments per X-spline segment
71             };
72             bless($self, $class);
73             }
74             return $self;
75             }
76              
77              
78             sub set_xy_fct
79             {
80             my $self = undef;
81             if($#_ < 1) {
82             croak "Usage: \$plot->set_xy_fct(function,[derivative-function])";
83             } else {
84             $self = shift;
85             $self->{'d1'} = shift;
86             if($#_ >= 0) {
87             $self->{'d2'} = shift;
88             }
89             $self->{'d'} = 0;
90             }
91             return $self;
92             }
93              
94              
95              
96             sub set_parametric_fct
97             {
98             my $self = undef;
99             if($#_ < 4) {
100             croak "Usage: \$plot->set_parametric_fct(min, max, xfct, yfct[, xderiv, yderiv]);";
101             } else {
102             $self = shift;
103             my $min = shift;
104             my $max = shift;
105             $self->{'r'} = [ $min, $max ];
106             $self->{'d1'} = shift;
107             $self->{'d2'} = shift;
108             $self->{'d'} = 2;
109             if($#_ >= 1) {
110             $self->{'d3'} = shift;
111             $self->{'d4'} = shift;
112             }
113             }
114             return $self;
115             }
116              
117              
118              
119             sub set_xy_points
120             {
121             my $self = undef;
122             if($#_ < 1) {
123             croak "Usage: \$plot->set_xy_points(pointsarrayref)";
124             } else {
125             $self = shift;
126             $self->{'d1'} = shift;
127             $self->{'d'} = 1;
128             }
129             return $self;
130             }
131              
132              
133              
134             sub set_xy_points_text
135             {
136             my $self = undef;
137             if($#_ < 1) {
138             croak "Usage: \$plot->set_xy_points_text(text)";
139             } else {
140             $self = shift;
141             my $text = shift;
142             my @array;
143             my $na = 0;
144             my $x;
145             my $y;
146             my $d;
147             foreach my $line (split(/\n/, $text)) {
148             $x = 0.0; $y = 0.0; $d = 0.0;
149             if($line =~ /\S/o) {
150             if($line =~ /^\s*(\S+)\s+(\S+)\s+(\S+)/o) {
151             $x = $1; $y = $2; $d = $3;
152             $array[$na++] = [ $x, $y, $d ];
153             } else {
154             if($line =~ /^\s*(\S+)\s+(\S+)/o) {
155             $x = $1; $y = $2;
156             $array[$na++] = [ $x, $y ];
157             } else {
158             croak "ERROR: Illegal line \"$line\" in text!";
159             }
160             }
161             }
162             }
163             $self->{'d1'} = \@array; $self->{'d'} = 1;
164             }
165             return $self;
166             }
167              
168              
169              
170             sub set_xy_points_file
171             {
172             my $self = undef;
173             if($#_ < 1) {
174             croak "Usage: \$plot->set_xy_points_file(filename)";
175             } else {
176             $self = shift; my $fn = shift; my $line;
177             my @array; my $na = 0;
178             my $x; my $y; my $d;
179             if(open(my $fh, '<', "$fn")) {
180             while(<$fh>) {
181             $line = $_; chomp $line;
182             if($line =~ /\S/o) {
183             if($line =~ /^\s*(\S+)\s+(\S+)\s+(\S+)/o) {
184             $x = $1; $y = $2; $d = $3;
185             $array[$na++] = [ $x, $y, $d ];
186             } else {
187             if($line =~ /^\s*(\S+)\s+(\S+)/o) {
188             $x = $1; $y = $2;
189             $array[$na++] = [ $x, $y ];
190             }
191             }
192             }
193             }
194             close($fh); $fh = undef;
195             $self->{'d1'} = \@array; $self->{'d'} = 1;
196             }
197             }
198             return $self;
199             }
200              
201              
202              
203             sub set_xsplines_points
204             {
205             my $self = undef;
206             my @pp; my $npp = 0; my $pr; my $x; my $y; my $s;
207             if($#_ < 1) {
208             croak "Usage: \$plot->set_xspline_points(arrayref [, s_default ])";
209             } else {
210             $self = shift;
211             my $ar = shift;
212             my $sdef = -1.0;
213             if($#_ >= 0) {
214             $sdef = shift;
215             if($sdef < -1.0) { $sdef = -1.0; }
216             if($sdef > 1.0) { $sdef = 1.0; }
217             }
218             for(my $i = 0; $i <= $#$ar; $i++) {
219             $pr = $ar->[$i];
220             if($#$pr > 0) {
221             $x = $pr->[0]; $y = $pr->[1]; $s = $sdef;
222             if($#$pr > 1) {
223             $s = $pr->[2];
224             if($s < -1.0) { $s = -1.0; }
225             if($s > 1.0) { $s = 1.0; }
226             }
227             $pp[$npp++] = [ $x, $y, $s ];
228             }
229             }
230             $self->{'d1'} = \@pp; $self->{'d'} = 3;
231             }
232             return $self;
233             }
234              
235              
236              
237             sub set_xsplines_points_text
238             {
239             my $self = undef;
240             if($#_ < 1) {
241             croak "Usage: \$plot->set_xsplines_points_text(text [, s_default ])";
242             } else {
243             $self = shift; my $t = shift; my $sdef = -1.0;
244             my $x; my $y; my $s;
245             my @pp; my $npp = 0;
246             if($#_ >= 0) {
247             $sdef = shift;
248             if($sdef < -1.0) { $sdef = -1.0; }
249             if($sdef > 1.0) { $sdef = 1.0; }
250             }
251             foreach my $line (split(/\n/, $t)) {
252             $x = 0.0; $y = 0.0; $s = $sdef;
253             if($line =~ /\S/o) {
254             if($line =~ /^\s*(\S+)\s+(\S+)\s+(\S+)/o) {
255             $x = $1; $y = $2; $s = $3;
256             if($s < -1.0) { $s = -1.0; }
257             if($s > 1.0) { $s = 1.0; }
258             $pp[$npp++] = [ $x, $y, $s ];
259             } else {
260             if($line =~ /^\s*(\S+)\s+(\S+)/o) {
261             $x = $1; $y = $2;
262             $pp[$npp++] = [ $x, $y, $sdef ];
263             }
264             }
265             }
266             }
267             $self->{'d1'} = \@pp; $self->{'d'} = 3;
268             }
269             return $self;
270             }
271              
272              
273              
274             sub set_xspline_points_file
275             {
276             my $self = undef;
277             if($#_ < 1) {
278             croak "Usage: \$plot->set_xspline_points_file(filename [, s_default ])";
279             } else {
280             $self = shift; my $fn = shift; my $sdef = -1; my $fh = undef;
281             my $line; my $x; my $y; my $s;
282             my @pp; my $npp = 0;
283             if($#_ >= 0) {
284             $sdef = shift;
285             if($sdef < -1.0) { $sdef = -1.0; }
286             if($sdef > 1.0) { $sdef = 1.0; }
287             }
288             if(open($fh, '<', $fn)) {
289             while(<$fh>) {
290             $line = $_; chomp $line;
291             $x = 0.0; $y = 0.0; $s = $sdef;
292             if($line =~ /\S/o) {
293             if($line =~/^\s*(\S+)\s+(\S+)\s+(\S+)/o) {
294             $x = $1; $y = $2; $s = $3;
295             if($s < -1.0) { $s = -1.0; }
296             if($s > 1.0) { $s = 1.0; }
297             $pp[$npp++] = [ $x, $y, $s ];
298             } else {
299             if($line =~/^\s*(\S+)\s+(\S+)/o) {
300             $x = $1; $y = $2;
301             $pp[$npp++] = [ $x, $y, $sdef ];
302             }
303             }
304             }
305             }
306             close($fh);
307             $self->{'d1'} = \@pp; $self->{'d'} = 3;
308             }
309             }
310             return $self;
311             }
312              
313              
314              
315             sub finish_points_points
316             {
317             my $self = shift;
318             $self->{'pp'} = $self->{'d1'};
319             return $self;
320             }
321              
322              
323              
324             sub finish_points_lines
325             {
326             my $self = shift;
327             $self->{'pp'} = $self->{'d1'};
328             return $self;
329             }
330              
331              
332              
333             sub finish_points_curve
334             {
335             my $self = shift;
336             $self->{'pp'} = $self->{'d1'};
337             return $self;
338             }
339              
340              
341              
342             sub finish_function_points
343             {
344             my $self = shift;
345             my @dp; # data points
346             my $ndp = 0; # Number of data points
347             my $xs = $self->{'ax'}->{'min'};
348             my $xe = $self->{'ax'}->{'max'};
349             my $rp = $self->{'range'};
350             my $x = 0.0;
351             my $y = 0.0;
352             if(defined($rp)) {
353             $xs = $rp->[0]; $xe = $rp->[1];
354             }
355             my $diff = $xe - $xs;
356             my $i = $self->{'i'};
357             if(defined($self->{'d1'})) {
358             my $fp = $self->{'d1'};
359             if($self->{'ax'}->{'t'}) {
360             $diff = exp(log($xe/$xs)/(1.0 * $i));
361             $x = $xs;
362             $y = &$fp($x);
363             $dp[0] = [ $x, $y ];
364             for(my $j = 1; $j < $i; $j++) {
365             $x = $x * $diff;
366             $y = &$fp($x);
367             $dp[$j] = [ $x, $y ];
368             }
369             $x = $xe;
370             $y = &$fp($x);
371             $dp[$i] = [ $x, $y ];
372             } else {
373             $x = $xs;
374             $y = &$fp($x);
375             $dp[0] = [ $x, $y ];
376             for(my $j = 1; $j < $i; $j++) {
377             $x = $xs + ((1.0 * $j) * $diff)/(1.0 * $i);
378             $y = &$fp($x);
379             $dp[$j] = [ $x, $y ];
380             }
381             $x = $xe;
382             $y = &$fp($x);
383             $dp[$i] = [ $x, $y ];
384             }
385             $self->{'pp'} = \@dp;
386             }
387             return $self;
388             }
389              
390              
391              
392             sub finish_function_curve
393             {
394             my $self = shift;
395             if(defined($self->{'d2'})) {
396             my @dp; # data points
397             my $ndp = 0; # Number of data points
398             my $xs = $self->{'ax'}->{'min'};
399             my $xe = $self->{'ax'}->{'max'};
400             my $rp = $self->{'range'};
401             my $x = 0.0;
402             my $y = 0.0;
403             my $z = 0.0;
404             if(defined($rp)) {
405             $xs = $rp->[0]; $xe = $rp->[1];
406             }
407             my $diff = $xe - $xs;
408             my $i = $self->{'i'};
409             if(defined($self->{'d1'})) {
410             my $fp = $self->{'d1'};
411             my $dfp = $self->{'d2'};
412             if($self->{'ax'}->{'t'}) {
413             $diff = exp(log($xe/$xs)/(1.0 * $i));
414             $x = $xs;
415             $y = &$fp($x);
416             $z = &$dfp($x);
417             $dp[0] = [ $x, $y, $z ];
418             for(my $j = 1; $j < $i; $j++) {
419             $x = $x * $diff;
420             $y = &$fp($x);
421             $z = &$dfp($x);
422             $dp[$j] = [ $x, $y, $z ];
423             }
424             $x = $xe;
425             $y = &$fp($x);
426             $z = &$dfp($x);
427             $dp[$i] = [ $x, $y, $z ];
428             } else {
429             $x = $xs;
430             $y = &$fp($x);
431             $z = &$dfp($x);
432             $dp[0] = [ $x, $y, $z ];
433             for(my $j = 1; $j < $i; $j++) {
434             $x = $xs + ((1.0 * $j) * $diff)/(1.0 * $i);
435             $y = &$fp($x);
436             $z = &$dfp($x);
437             $dp[$j] = [ $x, $y, $z ];
438             }
439             $x = $xe;
440             $y = &$fp($x);
441             $z = &$dfp($x);
442             $dp[$i] = [ $x, $y, $z ];
443             }
444             $self->{'pp'} = \@dp;
445             }
446             } else {
447             $self->finish_function_points();
448             }
449             return $self;
450             }
451              
452              
453              
454             sub finish_param_points
455             {
456             my $self = shift;
457             if(defined($self->{'r'}) && defined($self->{'d1'}) && defined($self->{'d2'}))
458             {
459             my @pp; my $npp = 0;
460             my $range = $self->{'r'}; my $fx = $self->{'d1'}; my $fy = $self->{'d2'};
461             my $mint = $range->[0]; my $maxt = $range->[1]; my $i = $self->{'i'};
462             my $x; my $y;
463             my $t;
464             $t = $mint;
465             $x = &$fx($t); $y = &$fy($t);
466             $pp[$npp++] = [ $t, $x, $y, undef, undef ];
467             for(my $j = 1; $j < $i; $j++) {
468             $t = $mint + ((1.0 * $j) * ($maxt - $mint)) / (1.0 * $i);
469             $x = &$fx($t); $y = &$fy($t);
470             $pp[$npp++] = [ $t, $x, $y, undef, undef ];
471             }
472             $t = $maxt;
473             $x = &$fx($t); $y = &$fy($t);
474             $pp[$npp++] = [ $t, $x, $y, undef, undef ];
475             $self->{'pp'} = \@pp;
476             }
477             return $self;
478             }
479              
480              
481              
482             sub finish_param_curve
483             {
484             my $self = shift;
485             if(defined($self->{'r'}) && defined($self->{'d1'}) && defined($self->{'d2'}))
486             {
487             my @pp; my $npp = 0;
488             my $range = $self->{'r'};
489             my $fx = $self->{'d1'}; my $fy = $self->{'d2'};
490             my $fxx = undef; my $fyy = undef;
491             if(defined($self->{'d3'}) && defined($self->{'d4'})) {
492             $fxx = $self->{'d3'}; $fyy = $self->{'d4'};
493             }
494             my $mint = $range->[0]; my $maxt = $range->[1]; my $i = $self->{'i'};
495             my $x; my $y; my $xx; my $yy;
496             my $t;
497             $t = $mint;
498             $x = &$fx($t); $y = &$fy($t); $xx = undef; $yy = undef;
499             if(defined($fxx)) { $xx = &$fxx($t); $yy = &$fyy($t); }
500             $pp[$npp++] = [ $t, $x, $y, $xx, $yy ];
501             for(my $j = 1; $j < $i; $j++) {
502             $t = $mint + ((1.0 * $j) * ($maxt - $mint)) / (1.0 * $i);
503             $x = &$fx($t); $y = &$fy($t); $xx = undef; $yy = undef;
504             if(defined($fxx)) { $xx = &$fxx($t); $yy = &$fyy($t); }
505             $pp[$npp++] = [ $t, $x, $y, $xx, $yy ];
506             }
507             $t = $maxt;
508             $x = &$fx($t); $y = &$fy($t); $xx = undef; $yy = undef;
509             if(defined($fxx)) { $xx = &$fxx($t); $yy = &$fyy($t); }
510             $pp[$npp++] = [ $t, $x, $y, $xx, $yy ];
511             $self->{'pp'} = \@pp;
512             }
513             return $self;
514             }
515              
516              
517              
518             sub finish
519             {
520             my $self = undef;
521             if($#_ < 0) {
522             croak "Usage: \$plot->finish()";
523             } else {
524             $self = shift;
525             if(!defined($self->{'f'})) {
526             my $pt = $self->{'t'};
527             my $dt = $self->{'d'};
528             if($pt == 0) {
529             if($dt == 0) {
530             $self->finish_function_points();
531             } else {
532             if($dt == 1) {
533             $self->finish_points_points();
534             } else {
535             if($dt == 2) {
536             $self->finish_param_points();
537             } else {
538             if($dt == 3) {
539             $self->finish_points_points();
540             }
541             }
542             }
543             }
544             } else {
545             if($pt == 1) {
546             if($dt == 0) {
547             $self->finish_function_curve();
548             } else {
549             if($dt == 1) {
550             $self->finish_points_curve();
551             } else {
552             if($dt == 2) {
553             $self->finish_param_curve();
554             } else {
555             if($dt == 3) {
556             $self->finish_points_points();
557             }
558             }
559             }
560             }
561             } else {
562             if($pt == 2) {
563             if($dt == 0) {
564             $self->finish_function_points();
565             } else {
566             if($dt == 1) {
567             $self->finish_points_lines();
568             } else {
569             if($dt == 2) {
570             $self->finish_param_points();
571             } else {
572             if($dt == 3) {
573             $self->finish_points_points();
574             }
575             }
576             }
577             }
578             }
579             }
580             }
581             $self->{'f'} = 1;
582             }
583             }
584             return $self;
585             }
586              
587              
588              
589             sub dot_circle
590             {
591             my $self = shift;
592             my $dg = shift;
593             my $fh = shift;
594             my $x = shift;
595             my $y = shift;
596             my $diameter = shift;
597             print $fh "\\pgfpathcircle{";
598             $dg->write_point($x, $y);
599             print $fh "}{" . (0.5 * $diameter) . "bp}\\pgfusepath{fill}\n";
600             return $self;
601             }
602              
603              
604              
605             sub dot_square
606             {
607             my $self = shift;
608             my $dg = shift;
609             my $fh = shift;
610             my $x = shift;
611             my $y = shift;
612             my $diameter = shift;
613             print $fh "\\pgfpathmoveto{";
614             $dg->write_point(($x - 0.5 * $diameter), ($y - 0.5 * $diameter));
615             print $fh "}\n";
616             print $fh "\\pgfpathlineto{";
617             $dg->write_point(($x + 0.5 * $diameter), ($y - 0.5 * $diameter));
618             print $fh "}\n";
619             print $fh "\\pgfpathlineto{";
620             $dg->write_point(($x + 0.5 * $diameter), ($y + 0.5 * $diameter));
621             print $fh "}\n";
622             print $fh "\\pgfpathlineto{";
623             $dg->write_point(($x - 0.5 * $diameter), ($y + 0.5 * $diameter));
624             print $fh "}\n\\pgfpathclose\\pgfusepath{fill}\n";
625             return $self;
626             }
627              
628              
629              
630             sub dot_diamond
631             {
632             my $self = shift;
633             my $dg = shift;
634             my $fh = shift;
635             my $x = shift;
636             my $y = shift;
637             my $diameter = shift;
638             my $d = $diameter / sqrt(2.0);
639             print $fh "\\pgfpathmoveto{";
640             $dg->write_point($x, ($y + $d));
641             print $fh "}\n";
642             print $fh "\\pgfpathlineto{";
643             $dg->write_point(($x - $d), $y);
644             print $fh "}\n";
645             print $fh "\\pgfpathlineto{";
646             $dg->write_point($x, ($y - $d));
647             print $fh "}\n";
648             print $fh "\\pgfpathlineto{";
649             $dg->write_point(($x + $d), $y);
650             print $fh "}\n\\pgfpathclose\\pgfusepath{fill}\n";
651             return $self;
652             }
653              
654              
655              
656             sub dot_triangle
657             {
658             my $self = shift;
659             my $dg = shift;
660             my $fh = shift;
661             my $x = shift;
662             my $y = shift;
663             my $diameter = shift;
664             my $a = 0.25 * $diameter;
665             my $b = 0.5 * sqrt(0.75) * $diameter;
666             print $fh "\\pgfpathmoveto{";
667             $dg->write_point($x, ($y + 0.5 * $diameter));
668             print $fh "}\n";
669             print $fh "\\pgfpathlineto{";
670             $dg->write_point(($x - $b), ($y - $a));
671             print $fh "}\n";
672             print $fh "\\pgfpathlineto{";
673             $dg->write_point(($x + $b), ($y - $a));
674             print $fh "}\n\\pgfpathclose\\pgfusepath{fill}\n";
675             return $self;
676             }
677              
678              
679              
680             sub dot_crosshair
681             {
682             my $self = shift;
683             my $dg = shift;
684             my $fh = shift;
685             my $x = shift;
686             my $y = shift;
687             my $diameter = shift;
688             print $fh "\\pgfpathmoveto{";
689             $dg->write_point($x, ($y + 0.5 * $diameter));
690             print $fh "}\n";
691             print $fh "\\pgfpathlineto{";
692             $dg->write_point($x, ($y - 0.5 * $diameter));
693             print $fh "}\n";
694             print $fh "\\pgfusepath{stroke}\n";
695             print $fh "\\pgfpathmoveto{";
696             $dg->write_point(($x - 0.5 * $diameter), $y);
697             print $fh "}\n";
698             print $fh "\\pgfpathlineto{";
699             $dg->write_point(($x + 0.5 * $diameter), $y);
700             print $fh "}\n\\pgfusepath{stroke}\n";
701             return $self;
702             }
703              
704              
705              
706             sub dot_pentagon
707             {
708             my $self = shift;
709             my $dg = shift;
710             my $fh = shift;
711             my $x = shift;
712             my $y = shift;
713             my $diameter = shift;
714             my $a = 0.5 * $diameter * cos(2.0 * 3.1415926 / 5.0);
715             my $b = 0.5 * $diameter * sin(2.0 * 3.1415926 / 5.0);
716             my $c = 0.5 * $diameter * cos(4.0 * 3.1415926 / 5.0);
717             my $d = 0.5 * $diameter * sin(4.0 * 3.1415926 / 5.0);
718             print $fh "\\pgfpathmoveto{";
719             $dg->write_point($x, ($y + 0.5 * $diameter));
720             print $fh "}\n";
721             print $fh "\\pgfpathlineto{";
722             $dg->write_point(($x - $b), ($y + $a));
723             print $fh "}\n";
724             print $fh "\\pgfpathlineto{";
725             $dg->write_point(($x - $d), ($y + $c));
726             print $fh "}\n";
727             print $fh "\\pgfpathlineto{";
728             $dg->write_point(($x + $d), ($y + $c));
729             print $fh "}\n";
730             print $fh "\\pgfpathlineto{";
731             $dg->write_point(($x + $b), ($y + $a));
732             print $fh "}\n\\pgfpathclose\\pgfusepath{fill}\n";
733             return $self;
734             }
735              
736              
737              
738             sub plot_points_points
739             {
740             my $self = shift; my $dg = shift;
741             my $fh = $dg->{'f1'};
742             my $aref = $self->{'pp'};
743             my $pref = undef; my $x = undef; my $y = undef;
744             my $diameter = $self->{'dsz'} * 0.2 * 72.0 / 25.4;
745             if($#$aref > 0) {
746             for(my $i = 0; $i <= $#$aref; $i++) {
747             $pref = $aref->[$i];
748             $x = $pref->[0]; $y = $pref->[1];
749             $x = $self->{'ax'}->value_to_coord($x);
750             $y = $self->{'ay'}->value_to_coord($y);
751             my $dt = $self->{'ds'};
752             if($dt == 0) {
753             $self->dot_circle($dg, $fh, $x, $y, $diameter);
754             }
755             if($dt == 1) {
756             $self->dot_square($dg, $fh, $x, $y, $diameter);
757             }
758             if($dt == 2) {
759             $self->dot_diamond($dg, $fh, $x, $y, $diameter);
760             }
761             if($dt == 3) {
762             $self->dot_triangle($dg, $fh, $x, $y, $diameter);
763             }
764             if($dt == 4) {
765             $self->dot_crosshair($dg, $fh, $x, $y, $diameter);
766             }
767             if($dt == 5) {
768             $self->dot_pentagon($dg, $fh, $x, $y, $diameter);
769             }
770             }
771             }
772             return $self;
773             }
774              
775              
776              
777             sub plot_points_lines
778             {
779             my $self = shift; my $dg = shift;
780             my $fh = $dg->{'f1'};
781             my $aref = $self->{'pp'};
782             my $pref = undef; my $x = undef; my $y = undef;
783             if($#$aref > 0) {
784             for(my $i = 0; $i <= $#$aref; $i++) {
785             $pref = $aref->[$i];
786             $x = $pref->[0]; $y = $pref->[1];
787             $x = $self->{'ax'}->value_to_coord($x);
788             $y = $self->{'ay'}->value_to_coord($y);
789             if($i == 0) {
790             print $fh "\\pgfpathmoveto{";
791             } else {
792             print $fh "\\pgfpathlineto{";
793             }
794             $dg->write_point($x, $y);
795             print $fh "}\n";
796             }
797             print $fh "\\pgfusepath{stroke}\n";
798             }
799             return $self;
800             }
801              
802              
803              
804             sub all_values_with_derivative
805             {
806             my $self = shift; my $dg = shift; my $pp = shift; my $fh = $dg->{'f1'};
807             my $pref = $pp->[0];
808             my $x = $pref->[0];
809             my $y = $pref->[1];
810             my $z = $pref->[2];
811             my $ox = $x; my $oy = $y; my $oz = $z; my $dxdt = undef; my $dydt = undef;
812             print $fh "\\pgfpathmoveto{";
813             $dg->write_point($x, $y);
814             print $fh "}\n";
815             for(my $i = 1; $i <= $#$pp; $i++) {
816             $pref = $pp->[$i];
817             $x = $pref->[0]; $y = $pref->[1]; $z = $pref->[2];
818             $dxdt = $x - $ox;
819             print $fh "\\pgfpathcurveto{";
820             $dydt = $oz * $dxdt;
821             $dg->write_point(($ox + ($dxdt/3.0)), ($oy + ($dydt/3.0)));
822             print $fh "}{";
823             $dydt = $z * $dxdt;
824             $dg->write_point(($x - ($dxdt/3.0)), ($y - ($dydt/3.0)));
825             print $fh "}{";
826             $dg->write_point($x, $y);
827             print $fh "}\n";
828             $ox = $x; $oy = $y; $oz = $z;
829             }
830             print $fh "\\pgfusepath{stroke}\n";
831             return $self;
832             }
833              
834              
835              
836             sub some_values_without_derivative
837             {
838             my $self = shift; my $dg = shift; my $pp = shift;
839             my $N = $#$pp + 1; # Number of points
840             my $nsegs = $N - 1; # Number of segments
841             my $neqs = 4 * $nsegs; # Number of equations and coefficients
842             my $eqnno; # Current equation
843             my $pref; # Reference to current point
844             my $j; # Number index
845             my $i; # Index of pref
846             my $x; # X coordinate
847             my $y; # Y coordinate
848             my $z; # first derivative (dy/dx)
849             my $mtx = zeros($neqs, $neqs); # Coefficients of eq sys
850             my $rve = zeros(1, $neqs); # Results vector of eq sys
851             # nsegs: 0 ... nsegs-1
852             for($j = 0; $j < $nsegs; $j++) {
853             $eqnno = $j; $i = $j;
854             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
855             $rve->set(0, $eqnno, $y);
856             $mtx->set((4*$j), $eqnno, ($x * $x * $x));
857             $mtx->set((4*$j+1), $eqnno, ($x * $x));
858             $mtx->set((4*$j+2), $eqnno, $x);
859             $mtx->set((4*$j+3), $eqnno, 1.0);
860             }
861             # nsegs: nsegs ... 2*nsegs-1
862             for($j = 0; $j < $nsegs; $j++) {
863             $eqnno = $nsegs + $j; $i = $j + 1;
864             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
865             $rve->set(0, $eqnno, $y);
866             $mtx->set((4*$j), $eqnno, ($x * $x * $x));
867             $mtx->set((4*$j+1), $eqnno, ($x * $x));
868             $mtx->set((4*$j+2), $eqnno, $x);
869             $mtx->set((4*$j+3), $eqnno, 1.0);
870             }
871             # nsegs-1: 2*nsegs ... 3*nsegs-2
872             for($j = 0; $j < ($nsegs - 1); $j++) {
873             $eqnno = 2 * $nsegs + $j; $i = $j + 1;
874             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
875             $mtx->set((4*$j), $eqnno, (3.0 * $x * $x));
876             $mtx->set((4*$j+1), $eqnno, (2.0 * $x));
877             $mtx->set((4*$j+2), $eqnno, 1.0);
878             $mtx->set((4*$i), $eqnno, (-3.0 * $x * $x));
879             $mtx->set((4*$i+1), $eqnno, (-2.0 * $x));
880             $mtx->set((4*$i+2), $eqnno, -1.0);
881             }
882             # nsegs-1: 3*nsegs-1 ... 4*nsegs-3
883             for($j = 0; $j < ($nsegs - 1); $j++) {
884             $eqnno = 3 * $nsegs - 1 + $j; $i = $j + 1;
885             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
886             if($#$pref > 1) {
887             $z = $pref->[2];
888             $mtx->set((4*$j), $eqnno, (3.0 * $x * $x));
889             $mtx->set((4*$j+1), $eqnno, (2.0 * $x));
890             $mtx->set((4*$j+2), $eqnno, 1.0);
891             $rve->set(0, $eqnno, $z);
892             } else {
893             $mtx->set((4*$j), $eqnno, (6.0 * $x));
894             $mtx->set((4*$j+1), $eqnno, 2.0);
895             $mtx->set((4*$i), $eqnno, (-6.0 * $x));
896             $mtx->set((4*$i+1), $eqnno, -2.0);
897             }
898             }
899             # 4*nsegs-2
900             $eqnno = 4 * $nsegs - 2; $j = 0; $i = 0;
901             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
902             if($#$pref > 1) {
903             $z = $pref->[2];
904             $mtx->set((4*$j), $eqnno, (3.0 * $x * $x));
905             $mtx->set((4*$j+1), $eqnno, (2.0 * $x));
906             $mtx->set((4*$j+2), $eqnno, 1.0);
907             $rve->set(0, $eqnno, $z);
908             } else {
909             $mtx->set((4*$j), $eqnno, (6.0 * $x));
910             $mtx->set((4*$j+1), $eqnno, 2.0);
911             }
912             # 4*nsegs-1
913             $eqnno = 4 * $nsegs - 1; $j = $nsegs - 1; $i = $j + 1;
914             $pref = $pp->[$i]; $x = $pref->[0]; $y = $pref->[1];
915             if($#$pref > 1) {
916             $z = $pref->[2];
917             $mtx->set((4*$j), $eqnno, (3.0 * $x * $x));
918             $mtx->set((4*$j+1), $eqnno, (2.0 * $x));
919             $mtx->set((4*$j+2), $eqnno, 1.0);
920             $rve->set(0, $eqnno, $z);
921             } else {
922             $mtx->set((4*$j), $eqnno, (6.0 * $x));
923             $mtx->set((4*$j+1), $eqnno, 2.0);
924             }
925             my $res = $mtx->inv() x $rve;
926             if($self->{'debug'}) {
927             print $res;
928             }
929             my @ppb; my $nppb = 0;
930             for($i = 0; $i <= $#$pp; $i++) {
931             $pref = $pp->[$i];
932             $x = $pref->[0]; $y = $pref->[1]; $z = 0.0;
933             if($#$pref > 1) {
934             $z = $pref->[2];
935             } else {
936             if($i > 0) {
937             $z = 3.0 * $res->at(0, 4*($i-1)) * $x * $x
938             + 2.0 * $res->at(0, 4*($i-1)+1) * $x
939             + $res->at(0, 4*($i-1)+2);
940             } else {
941             $z = 3.0 * $res->at(0, 0) * $x * $x
942             + 2.0 * $res->at(0, 1) * $x
943             + $res->at(0, 2);
944             }
945             }
946             $ppb[$i] = [ $x, $y, $z ];
947             }
948             $self->all_values_with_derivative($dg, \@ppb);
949             return $self;
950             }
951              
952              
953              
954             sub plot_points_curve
955             {
956             my $self = shift; my $dg = shift;
957             my @ppa; my $nppa = 0;
958             my $aref = $self->{'pp'};
959             my $pref = undef;
960             my $ax = $self->{'ax'}; my $ay = $self->{'ay'};
961             my $x = undef;
962             my $y = undef;
963             my $z = undef;
964             my $value_without_derivative = 0;
965             for(my $i = 0; $i <= $#$aref; $i++) {
966             $pref = $aref->[$i];
967             $z = undef;
968             $x = $pref->[0]; $y = $pref->[1];
969             if($#$pref > 1) {
970             $z = $pref->[2]
971             * $ay->value_to_derivative($y) / $ax->value_to_derivative($x);
972             } else {
973             $value_without_derivative = 1;
974             }
975             $x = $self->{'ax'}->value_to_coord($x);
976             $y = $self->{'ay'}->value_to_coord($y);
977             if(defined($z)) {
978             $ppa[$nppa++] = [ $x, $y, $z ];
979             } else {
980             $ppa[$nppa++] = [ $x, $y ];
981             }
982             }
983             my @ppb = sort { $a->[0] <=> $b->[0]; } @ppa;
984             if($value_without_derivative) {
985             $self->some_values_without_derivative($dg, \@ppb);
986             } else {
987             $self->all_values_with_derivative($dg, \@ppb);
988             }
989             return $self;
990             }
991              
992              
993              
994             sub plot_param_points
995             {
996             my $self = shift; my $dg = shift; my $fh = $dg->{'f1'};
997             my $ar = $self->{'pp'};
998             my $pr = undef;
999             my $x = undef;
1000             my $y = undef;
1001             my $dt = $self->{'ds'};
1002             my $diameter = $self->{'dsz'} * 0.2 * 72.0 / 25.4;
1003             for(my $i = 0; $i <= $#$ar; $i++) {
1004             $pr = $ar->[$i];
1005             $x = $pr->[1];
1006             $y = $pr->[2];
1007             $x = $self->{'ax'}->value_to_coord($x);
1008             $y = $self->{'ay'}->value_to_coord($y);
1009             if($dt == 0) {
1010             $self->dot_circle($dg, $fh, $x, $y, $diameter);
1011             }
1012             if($dt == 1) {
1013             $self->dot_square($dg, $fh, $x, $y, $diameter);
1014             }
1015             if($dt == 2) {
1016             $self->dot_diamond($dg, $fh, $x, $y, $diameter);
1017             }
1018             if($dt == 3) {
1019             $self->dot_triangle($dg, $fh, $x, $y, $diameter);
1020             }
1021             if($dt == 4) {
1022             $self->dot_crosshair($dg, $fh, $x, $y, $diameter);
1023             }
1024             if($dt == 5) {
1025             $self->dot_pentagon($dg, $fh, $x, $y, $diameter);
1026             }
1027             }
1028             return $self;
1029             }
1030              
1031              
1032              
1033             sub plot_param_lines
1034             {
1035             my $self = shift; my $dg = shift; my $fh = $dg->{'f1'};
1036             my $ar = $self->{'pp'};
1037             my $pr = undef;
1038             my $x = undef;
1039             my $y = undef;
1040             if($#$ar >= 1) {
1041             $pr = $ar->[0];
1042             $x = $self->{'ax'}->value_to_coord($pr->[1]);
1043             $y = $self->{'ax'}->value_to_coord($pr->[2]);
1044             print $fh "\\pgfpathmoveto{";
1045             $dg->write_point($x, $y);
1046             print $fh "}\n";
1047             for(my $i = 1; $i <= $#$ar; $i++) {
1048             $pr = $ar->[$i];
1049             $x = $self->{'ax'}->value_to_coord($pr->[1]);
1050             $y = $self->{'ax'}->value_to_coord($pr->[2]);
1051             print $fh "\\pgfpathlineto{";
1052             $dg->write_point($x, $y);
1053             print $fh "}\n";
1054             }
1055             print $fh "\\pgfusepath{stroke}\n";
1056             }
1057             return $self;
1058             }
1059              
1060              
1061              
1062             sub check_param_derivatives
1063             {
1064             my $self = shift;
1065             my $back = 1;
1066             my $ar; my $pr;
1067             $ar = $self->{'pp'};
1068             for(my $i = 0; $i <= $#$ar; $i++) {
1069             $pr = $ar->[$i];
1070             if(!(defined($pr->[3]) && defined($pr->[4]))) {
1071             $back = 0; $i = $#$ar + 1;
1072             }
1073             }
1074             return $back;
1075             }
1076              
1077              
1078              
1079             sub do_param_with_all_derivatives
1080             {
1081             my $self = shift;
1082             my $dg = shift;
1083             my $pp = shift;
1084             my $fh = $dg->{'f1'};
1085             my $ox; my $oy; my $odxdt; my $odydt; my $x; my $y; my $dxdt; my $dydt;
1086             my $pr;
1087             $pr = $pp->[0];
1088             $x = $pr->[1]; $y = $pr->[2]; $dxdt = $pr->[3]; $dydt = $pr->[4];
1089             print $fh "\\pgfpathmoveto{";
1090             $dg->write_point($x, $y);
1091             print $fh "}\n";
1092             $ox = $x; $oy = $y; $odxdt = $dxdt; $odydt = $dydt;
1093             for(my $i = 1; $i <= $#$pp; $i++) {
1094             $pr = $pp->[$i];
1095             $x = $pr->[1]; $y = $pr->[2]; $dxdt = $pr->[3]; $dydt = $pr->[4];
1096             print $fh "\\pgfpathcurveto{";
1097             $dg->write_point(($ox + $odxdt/3.0), ($oy + $odydt/3.0));
1098             print $fh "}{";
1099             $dg->write_point(($x - $dxdt/3.0), ($y - $dydt/3.0));
1100             print $fh "}{";
1101             $dg->write_point($x, $y);
1102             print $fh "}\n";
1103             $ox = $x; $oy = $y; $odxdt = $dxdt; $odydt = $dydt;
1104             }
1105             print $fh "\\pgfusepath{stroke}\n";
1106             return $self;
1107             }
1108              
1109              
1110             sub param_with_all_derivatives
1111             {
1112             my $self = shift; my $dg = shift;
1113             my $fh = $dg->{'f1'};
1114             my @npp;
1115             my $ar = $self->{'pp'};
1116             my $pr;
1117             my $t; my $x; my $y; my $xx; my $yy;
1118             my $r = $self->{'r'};
1119             my $mint = $r->[0]; my $maxt = $r->[1];
1120             my $dTdt = ($maxt - $mint) / (1.0 * $self->{'i'});
1121             my $ax = $self->{'ax'}; my $ay = $self->{'ay'};
1122             for(my $i = 0; $i <= $#$ar; $i++) {
1123             $pr = $ar->[$i];
1124             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2]; $xx = $pr->[3]; $yy = $pr->[4];
1125             $xx = $xx * $ax->value_to_derivative($x) * $dTdt;
1126             $yy = $yy * $ay->value_to_derivative($y) * $dTdt;
1127             $x = $ax->value_to_coord($x);
1128             $y = $ay->value_to_coord($y);
1129             $npp[$i] = [ $t, $x, $y, $xx, $yy ];
1130             }
1131             $self->do_param_with_all_derivatives($dg, \@npp);
1132             return $self;
1133             }
1134              
1135              
1136              
1137             sub find_missing_derivatives
1138             {
1139             my $self = shift; my $dg = shift; my $pp = $self->{'pp'};
1140             my @npp;
1141             my $pr;
1142             my $t; my $x; my $y; my $xx; my $yy;
1143             my $N = $#$pp + 1;
1144             my $nsegs = $N - 1;
1145             my $ax = $self->{'ax'}; my $ay = $self->{'ay'};
1146             my $i;
1147             my $eqnno;
1148             for($i = 0; $i <= $#$pp; $i++) {
1149             $pr = $pp->[$i];
1150             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2]; $xx = undef; $yy = undef;
1151             $x = $ax->value_to_coord($x);
1152             $y = $ay->value_to_coord($y);
1153             $npp[$i] = [ (1.0 * $i) , $x, $y, $xx, $yy ];
1154             }
1155             my $xmtx = zeros((4 * $nsegs), (4 * $nsegs));
1156             my $ymtx = zeros((4 * $nsegs), (4 * $nsegs));
1157             my $xres = zeros(1, (4 * $nsegs));
1158             my $yres = zeros(1, (4 * $nsegs));
1159             for($i = 0; $i < $nsegs; $i++) {
1160             $eqnno = $i;
1161             $pr = $npp[$i];
1162             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1163             $xres->set(0, $eqnno, $x);
1164             $xmtx->set((4 * $i), $eqnno, ($t*$t*$t));
1165             $xmtx->set((4 * $i + 1), $eqnno, ($t * $t));
1166             $xmtx->set((4 * $i + 2), $eqnno, $t);
1167             $xmtx->set((4 * $i + 3), $eqnno, 1.0);
1168             $yres->set(0, $eqnno, $y);
1169             $ymtx->set((4 * $i), $eqnno, ($t * $t * $t));
1170             $ymtx->set((4 * $i + 1), $eqnno, ($t * $t));
1171             $ymtx->set((4 * $i + 2), $eqnno, $t);
1172             $ymtx->set((4 * $i + 3), $eqnno, 1.0);
1173             }
1174             for($i = 0; $i < $nsegs; $i++) {
1175             $eqnno = $nsegs + $i;
1176             $pr = $npp[$i + 1];
1177             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1178             $xres->set(0, $eqnno, $x);
1179             $xmtx->set((4 * $i), $eqnno, ($t * $t * $t));
1180             $xmtx->set((4 * $i + 1), $eqnno, ($t * $t));
1181             $xmtx->set((4 * $i + 2), $eqnno, $t);
1182             $xmtx->set((4 * $i + 3), $eqnno, 1.0);
1183             $yres->set(0, $eqnno, $y);
1184             $ymtx->set((4 * $i), $eqnno, ($t * $t * $t));
1185             $ymtx->set((4 * $i + 1), $eqnno, ($t * $t));
1186             $ymtx->set((4 * $i + 2), $eqnno, $t);
1187             $ymtx->set((4 * $i + 3), $eqnno, 1.0);
1188             }
1189             for($i = 0; $i < ($nsegs - 1); $i++) {
1190             $eqnno = 2 * $nsegs + $i;
1191             $pr = $npp[$i + 1];
1192             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1193             $xmtx->set((4 * $i), $eqnno, (3.0 * $t * $t));
1194             $xmtx->set((4 * $i + 1), $eqnno, (2.0 * $t));
1195             $xmtx->set((4 * $i + 2), $eqnno, 1.0);
1196             $xmtx->set((4 * ($i + 1)), $eqnno, (-3.0 * $t * $t));
1197             $xmtx->set((4 * ($i + 1) + 1), $eqnno, (-2.0 * $t));
1198             $xmtx->set((4 * ($i + 1) + 2), $eqnno, -1.0);
1199             $ymtx->set((4 * $i), $eqnno, (3.0 * $t * $t));
1200             $ymtx->set((4 * $i + 1), $eqnno, (2.0 * $t));
1201             $ymtx->set((4 * $i + 2), $eqnno, 1.0);
1202             $ymtx->set((4 * ($i + 1)), $eqnno, (-3.0 * $t * $t));
1203             $ymtx->set((4 * ($i + 1) + 1), $eqnno, (-2.0 * $t));
1204             $ymtx->set((4 * ($i + 1) + 2), $eqnno, -1.0);
1205             }
1206             for($i = 0; $i < ($nsegs - 1); $i++) {
1207             $eqnno = 3 * $nsegs - 1 + $i;
1208             $pr = $npp[$i + 1];
1209             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1210             $xmtx->set((4 * $i), $eqnno, (6.0 * $t));
1211             $xmtx->set((4 * $i + 1), $eqnno, 2.0);
1212             $xmtx->set((4 * ($i + 1)), $eqnno, (-6.0 * $t));
1213             $xmtx->set((4 * ($i + 1) + 1), $eqnno, -2.0);
1214             $ymtx->set((4 * $i), $eqnno, (6.0 * $t));
1215             $ymtx->set((4 * $i + 1), $eqnno, 2.0);
1216             $ymtx->set((4 * ($i + 1)), $eqnno, (-6.0 * $t));
1217             $ymtx->set((4 * ($i + 1) + 1), $eqnno, -2.0);
1218             }
1219             $i = 0; $eqnno = 4 * $nsegs - 2;
1220             $pr = $npp[0];
1221             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1222             $xmtx->set((4 * $i), $eqnno, (6.0 * $t));
1223             $xmtx->set((4 * $i + 1), $eqnno, 2.0);
1224             $ymtx->set((4 * $i), $eqnno, (6.0 * $t));
1225             $ymtx->set((4 * $i + 1), $eqnno, 2.0);
1226             $i = $nsegs - 1; $eqnno = 4 * $nsegs - 1;
1227             $pr = $npp[$nsegs];
1228             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1229             $xmtx->set((4 * $i), $eqnno, (6.0 * $t));
1230             $xmtx->set((4 * $i + 1), $eqnno, 2.0);
1231             $ymtx->set((4 * $i), $eqnno, (6.0 * $t));
1232             $ymtx->set((4 * $i + 1), $eqnno, 2.0);
1233             my $xco = $xmtx->inv() x $xres;
1234             my $yco = $ymtx->inv() x $yres;
1235             for($i = 0; $i < $#npp; $i++) {
1236             $pr = $npp[$i];
1237             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1238             $xx = 3.0 * $xco->at(0, (4 * $i)) * $t * $t
1239             + 2.0 * $xco->at(0, (4 * $i + 1)) * $t
1240             + $xco->at(0, (4 * $i + 2));
1241             $yy = 3.0 * $yco->at(0, (4 * $i)) * $t * $t
1242             + 2.0 * $yco->at(0, (4 * $i + 1)) * $t
1243             + $yco->at(0, (4 * $i + 2));
1244             $pr->[3] = $xx; $pr->[4] = $yy;
1245             }
1246             $i = $#npp - 1;
1247             $pr = $npp[ $#npp ];
1248             $t = $pr->[0]; $x = $pr->[1]; $y = $pr->[2];
1249             $xx = 3.0 * $xco->at(0, (4 * $i)) * $t * $t
1250             + 2.0 * $xco->at(0, (4 * $i + 1)) * $t
1251             + $xco->at(0, (4 * $i + 2));
1252             $yy = 3.0 * $yco->at(0, (4 * $i)) * $t * $t
1253             + 2.0 * $yco->at(0, (4 * $i + 1)) * $t
1254             + $yco->at(0, (4 * $i + 2));
1255             $pr->[3] = $xx; $pr->[4] = $yy;
1256             $self->do_param_with_all_derivatives($dg, \@npp);
1257             }
1258              
1259              
1260              
1261             sub plot_param_curve
1262             {
1263             my $self = shift; my $dg = shift;
1264             if($self->check_param_derivatives($dg)) {
1265             $self->param_with_all_derivatives($dg);
1266             } else {
1267             $self->find_missing_derivatives($dg);
1268             }
1269             return $self;
1270             }
1271              
1272              
1273              
1274             sub plot_xspline_curve
1275             {
1276             my $self = shift;
1277             my $dg = shift;
1278             my $fh = $dg->{'f1'};
1279             my $xs = LaTeX::PGF::Diagram2D::Xspline->new();
1280             my @pp; my $npp = 0;
1281             my $ar = $self->{'pp'};
1282             my $ax = $self->{'ax'};
1283             my $ay = $self->{'ay'};
1284             my $x;
1285             my $y;
1286             my $s;
1287             my $dxdt;
1288             my $dydt;
1289             my $odxdt;
1290             my $odydt;
1291             my $ox;
1292             my $oy;
1293             my $b; # Current start point of segment
1294             my $a; # Left neighbour
1295             my $c; # Current end point of segment
1296             my $d; # Right neighbour
1297             my $pa; my $pb; my $pc; my $pd;
1298             for($npp = 0; $npp <= $#$ar; $npp++) {
1299             $pa = $ar->[$npp];
1300             $x = $pa->[0]; $y = $pa->[1];
1301             $s = -1.0;
1302             if($#$pa > 1) {
1303             $s = $pa->[2];
1304             }
1305             $x = $ax->value_to_coord($x);
1306             $y = $ay->value_to_coord($y);
1307             $pp[$npp] = [ $x, $y, $s ];
1308             }
1309             $ar = \@pp;
1310             my $subs = $self->{'xspline'}; ; my $i; my $t;
1311             for($b = 0; $b < $#pp; $b++) {
1312             $a = $b - 1; $c = $b + 1; $d = $b + 2;
1313             $pa = undef; $pb = undef; $pc = undef; $pd = undef;
1314             if($a >= 0) { $pa = $pp[$a]; }
1315             $pb = $pp[$b];
1316             $pc = $pp[$c];
1317             if($d <= $#pp) { $pd = $pp[$d]; }
1318             $xs->set_points($pa, $pb, $pc, $pd);
1319             $xs->calculate(0.0);
1320             $odxdt = $xs->{'ddtx'} / (1.0 * $subs);
1321             $odydt = $xs->{'ddty'} / (1.0 * $subs);
1322             $ox = $xs->{'x'}; my $oy = $xs->{'y'};
1323             if($b == 0) {
1324             print $fh "\\pgfpathmoveto{";
1325             $dg->write_point($ox, $oy);
1326             print $fh "}\n";
1327             }
1328             for($i = 1; $i < $subs; $i++) {
1329             $t = (1.0 * $i) / (1.0 * $subs);
1330             $xs->calculate($t);
1331             $x = $xs->{'x'}; $y = $xs->{'y'};
1332             $dxdt = $xs->{'ddtx'} / (1.0 * $subs);
1333             $dydt = $xs->{'ddty'} / (1.0 * $subs);
1334             print $fh "\\pgfpathcurveto{\n";
1335             $dg->write_point(($ox + ($odxdt / 3.0)), ($oy + ($odydt / 3.0)));
1336             print $fh "}{";
1337             $dg->write_point(($x - ($dxdt / 3.0)), ($y - ($dydt / 3.0)));
1338             print $fh "}{";
1339             $dg->write_point($x, $y);
1340             print $fh "}\n";
1341             $ox = $x; $oy = $y; $odxdt = $dxdt; $odydt = $dydt;
1342             }
1343             $t = 1.0;
1344             $xs->calculate($t);
1345             $x = $xs->{'x'}; $y = $xs->{'y'};
1346             $dxdt = $xs->{'ddtx'} / (1.0 * $subs);
1347             $dydt = $xs->{'ddty'} / (1.0 * $subs);
1348             print $fh "\\pgfpathcurveto{\n";
1349             $dg->write_point(($ox + ($odxdt / 3.0)), ($oy + ($odydt / 3.0)));
1350             print $fh "}{";
1351             $dg->write_point(($x - ($dxdt / 3.0)), ($y - ($dydt / 3.0)));
1352             print $fh "}{";
1353             $dg->write_point($x, $y);
1354             print $fh "}\n";
1355             $ox = $x; $oy = $y; $odxdt = $dxdt; $odydt = $dydt;
1356             }
1357             print $fh "\\pgfusepath{stroke}\n";
1358             }
1359              
1360              
1361              
1362             sub plot_to
1363             {
1364             my $self = undef;
1365             if($#_ < 1) {
1366             croak "Usage: \$plot->plot_to(diagram)";
1367             } else {
1368             $self = shift; my $dg = shift;
1369             $self->finish();
1370             my $color = 'black';
1371             if(defined($self->{'color'})) {
1372             $color = $self->{'color'};
1373             }
1374             $dg->set_color($color);
1375             my $pt = $self->{'t'};
1376             my $dt = $self->{'d'};
1377             if($pt == 0) {
1378             if($dt == 0) {
1379             $self->plot_points_points($dg);
1380             } else {
1381             if($dt == 1) {
1382             $self->plot_points_points($dg);
1383             } else {
1384             if($dt == 2) {
1385             $self->plot_param_points($dg);
1386             } else {
1387             if($dt == 3) {
1388             $self->plot_points_points($dg);
1389             }
1390             }
1391             }
1392             }
1393             } else {
1394             if($pt == 1) {
1395             if($dt == 0) {
1396             $self->plot_points_curve($dg);
1397             } else {
1398             if($dt == 1) {
1399             $self->plot_points_curve($dg);
1400             } else {
1401             if($dt == 2) {
1402             $self->plot_param_curve($dg);
1403             } else {
1404             if($dt == 3) {
1405             $self->plot_xspline_curve($dg);
1406             }
1407             }
1408             }
1409             }
1410             } else {
1411             if($pt == 2) {
1412             if($dt == 0) {
1413             $self->plot_points_lines($dg);
1414             } else {
1415             if($dt == 1) {
1416             $self->plot_points_lines($dg);
1417             } else {
1418             if($dt == 2) {
1419             $self->plot_param_lines($dg);
1420             } else {
1421             if($dt == 3) {
1422             $self->plot_points_lines($dg);
1423             }
1424             }
1425             }
1426             }
1427             }
1428             }
1429             }
1430             }
1431             return $self;
1432             }
1433              
1434              
1435             sub set_curve
1436             {
1437             my $self = undef;
1438             if($#_ < 0) {
1439             croak "Usage: \$plot->set_lines()";
1440             } else {
1441             $self = shift; $self->{'t'} = 1;
1442             }
1443             return $self;
1444             }
1445              
1446              
1447             sub set_lines
1448             {
1449             my $self = undef;
1450             if($#_ < 0) {
1451             croak "Usage: \$plot->set_lines()";
1452             } else {
1453             $self = shift; $self->{'t'} = 2;
1454             }
1455             return $self;
1456             }
1457              
1458              
1459              
1460             sub set_dots
1461             {
1462             my $self = undef;
1463             if($#_ < 0) {
1464             croak "Usage: \$plot->set_dots([dotstyle])";
1465             } else {
1466             $self = shift; $self->{'t'} = 0; $self->{'ds'} = 0;
1467             if($#_ >= 0) {
1468             my $t = shift;
1469             if(("$t" eq "0") || ("$t" eq "c") || ("$t" eq "circle")) {
1470             $self->{'ds'} = 0;
1471             }
1472             if(("$t" eq "1") || ("$t" eq "s") || ("$t" eq "square")) {
1473             $self->{'ds'} = 1;
1474             }
1475             if(("$t" eq "2") || ("$t" eq "d") || ("$t" eq "diamond")) {
1476             $self->{'ds'} = 2;
1477             }
1478             if(("$t" eq "3") || ("$t" eq "t") || ("$t" eq "triangle")) {
1479             $self->{'ds'} = 3;
1480             }
1481             if(("$t" eq "4") || ("$t" eq "cr") || ("$t" eq "crosshair")) {
1482             $self->{'ds'} = 4;
1483             }
1484             if(("$t" eq "5") || ("$t" eq "p") || ("$t" eq "pentagon")) {
1485             $self->{'ds'} = 5;
1486             }
1487             if($#_ >= 0) {
1488             $self->{'dsz'} = shift;
1489             }
1490             }
1491             }
1492             return $self;
1493             }
1494              
1495              
1496              
1497             sub debug
1498             {
1499             my $self = undef;
1500             if($#_ >= 0) {
1501             $self = shift;
1502             my $msg = ""; my $i = 0;
1503             while($#_ > -1) {
1504             if($i) {
1505             $msg = "$msg " . shift;
1506             } else {
1507             $msg = shift;
1508             }
1509             $i++;
1510             }
1511             if($self->{'debug'}) {
1512             print "DEBUG $msg\n";
1513             }
1514             }
1515             return $self;
1516             }
1517              
1518              
1519              
1520             sub set_intervals
1521             {
1522             my $self = undef;
1523             if($#_ < 1) {
1524             croak "Usage: \$plot->set_intervals(number)";
1525             } else {
1526             $self = shift;
1527             my $n = shift;
1528             if($n < 1) {
1529             croak "ERROR: At least one interval is needed!";
1530             } else {
1531             $self->{'i'} = $n;
1532             }
1533             }
1534             return $self;
1535             }
1536              
1537              
1538              
1539             sub set_color
1540             {
1541             my $self = undef;
1542             if($#_ < 1) {
1543             croak "Usage: \$plot->set_color(color)";
1544             } else {
1545             $self = shift; $self->{'color'} = shift;
1546             }
1547             return $self;
1548             }
1549              
1550              
1551              
1552             sub set_xsplines_segments
1553             {
1554             my $self = undef;
1555             if($#_ >= 1) {
1556             $self = shift; $self->{'xspline'} = shift;
1557             } else {
1558             croak "Usage: \$plot->set_xsplines_segments(num)";
1559             }
1560             return $self;
1561             }
1562              
1563              
1564              
1565             sub set_range
1566             {
1567             my $self = undef;
1568             if($#_ >= 2) {
1569             $self = shift; my $min = shift; my $max = shift;
1570             $self->{'r'} = [ $min, $max ];
1571             } else {
1572             croak "Usage: \$plot->set_range(min, max)";
1573             }
1574             return $self;
1575             }
1576              
1577              
1578             1;
1579              
1580             __END__