Subversion Repositories Sites.obs-saisons.fr

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 aurelien 1
<?php
2
/*=======================================================================
3
// File: 	JPGRAPH_LINE.PHP
4
// Description:	Line plot extension for JpGraph
5
// Created: 	2001-01-08
6
// Ver:		$Id: jpgraph_line.php 982 2008-03-24 11:51:47Z ljp $
7
//
8
// Copyright (c) Aditus Consulting. All rights reserved.
9
//========================================================================
10
*/
11
 
12
require_once ('jpgraph_plotmark.inc.php');
13
 
14
// constants for the (filled) area
15
DEFINE("LP_AREA_FILLED", true);
16
DEFINE("LP_AREA_NOT_FILLED", false);
17
DEFINE("LP_AREA_BORDER",false);
18
DEFINE("LP_AREA_NO_BORDER",true);
19
 
20
//===================================================
21
// CLASS LinePlot
22
// Description:
23
//===================================================
24
class LinePlot extends Plot{
25
    var $filled=false;
26
    var $fill_color='blue';
27
    var $mark=null;
28
    var $step_style=false, $center=false;
29
    var $line_style=1;	// Default to solid
30
    var $filledAreas = array(); // array of arrays(with min,max,col,filled in them)
31
    var $barcenter=false;  // When we mix line and bar. Should we center the line in the bar.
32
    var $fillFromMin = false ;
33
    var $fillgrad=false,$fillgrad_fromcolor='navy',$fillgrad_tocolor='silver',$fillgrad_numcolors=100;
34
    var $iFastStroke=false;
35
 
36
//---------------
37
// CONSTRUCTOR
38
    function LinePlot(&$datay,$datax=false) {
39
	$this->Plot($datay,$datax);
40
	$this->mark = new PlotMark();
41
    }
42
//---------------
43
// PUBLIC METHODS
44
 
45
    // Set style, filled or open
46
    function SetFilled($aFlag=true) {
47
    	JpGraphError::RaiseL(10001);//('LinePlot::SetFilled() is deprecated. Use SetFillColor()');
48
    }
49
 
50
    function SetBarCenter($aFlag=true) {
51
	$this->barcenter=$aFlag;
52
    }
53
 
54
    function SetStyle($aStyle) {
55
	$this->line_style=$aStyle;
56
    }
57
 
58
    function SetStepStyle($aFlag=true) {
59
	$this->step_style = $aFlag;
60
    }
61
 
62
    function SetColor($aColor) {
63
	parent::SetColor($aColor);
64
    }
65
 
66
    function SetFillFromYMin($f=true) {
67
	$this->fillFromMin = $f ;
68
    }
69
 
70
    function SetFillColor($aColor,$aFilled=true) {
71
	$this->fill_color=$aColor;
72
	$this->filled=$aFilled;
73
    }
74
 
75
    function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) {
76
	$this->fillgrad_fromcolor = $aFromColor;
77
	$this->fillgrad_tocolor   = $aToColor;
78
	$this->fillgrad_numcolors = $aNumColors;
79
	$this->filled = $aFilled;
80
	$this->fillgrad = true;
81
    }
82
 
83
    function Legend(&$graph) {
84
	if( $this->legend!="" ) {
85
	    if( $this->filled && !$this->fillgrad ) {
86
		$graph->legend->Add($this->legend,
87
				    $this->fill_color,$this->mark,0,
88
				    $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
89
	    }
90
	    elseif( $this->fillgrad ) {
91
		$color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor);
92
		// In order to differentiate between gradients and cooors specified as an RGB triple
93
		$graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */,
94
				    $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
95
	    }
96
	    else {
97
		$graph->legend->Add($this->legend,
98
				    $this->color,$this->mark,$this->line_style,
99
				    $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
100
	    }
101
	}
102
    }
103
 
104
    function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) {
105
	if($aMin > $aMax) {
106
	    // swap
107
	    $tmp = $aMin;
108
	    $aMin = $aMax;
109
	    $aMax = $tmp;
110
	}
111
	$this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder);
112
    }
113
 
114
    // Gets called before any axis are stroked
115
    function PreStrokeAdjust(&$graph) {
116
 
117
	// If another plot type have already adjusted the
118
	// offset we don't touch it.
119
	// (We check for empty in case the scale is  a log scale
120
	// and hence doesn't contain any xlabel_offset)
121
	if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||
122
	    $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
123
	    if( $this->center ) {
124
		++$this->numpoints;
125
		$a=0.5; $b=0.5;
126
	    } else {
127
		$a=0; $b=0;
128
	    }
129
	    $graph->xaxis->scale->ticks->SetXLabelOffset($a);
130
	    $graph->SetTextScaleOff($b);
131
	    //$graph->xaxis->scale->ticks->SupressMinorTickMarks();
132
	}
133
    }
134
 
135
    function SetFastStroke($aFlg=true) {
136
	$this->iFastStroke = $aFlg;
137
    }
138
 
139
    function FastStroke(&$img,&$xscale,&$yscale,$aStartPoint=0,$exist_x=true) {
140
	// An optimized stroke for many data points with no extra
141
	// features but 60% faster. You can't have values or line styles, or null
142
	// values in plots.
143
	$numpoints=count($this->coords[0]);
144
	if( $this->barcenter )
145
	    $textadj = 0.5-$xscale->text_scale_off;
146
	else
147
	    $textadj = 0;
148
 
149
	$img->SetColor($this->color);
150
	$img->SetLineWeight($this->weight);
151
	$pnts=$aStartPoint;
152
	while( $pnts < $numpoints ) {
153
	    if( $exist_x ) $x=$this->coords[1][$pnts];
154
	    else $x=$pnts+$textadj;
155
	    $xt = $xscale->Translate($x);
156
	    $y=$this->coords[0][$pnts];
157
	    $yt = $yscale->Translate($y);
158
	    if( is_numeric($y) ) {
159
		$cord[] = $xt;
160
		$cord[] = $yt;
161
	    }
162
	    elseif( $y == '-' && $pnts > 0 ) {
163
		// Just ignore
164
	    }
165
	    else {
166
		JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()');
167
		return;
168
	    }
169
	    ++$pnts;
170
	} // WHILE
171
 
172
	$img->Polygon($cord,false,true);
173
 
174
    }
175
 
176
    function Stroke(&$img,&$xscale,&$yscale) {
177
	$idx=0;
178
	$numpoints=count($this->coords[0]);
179
	if( isset($this->coords[1]) ) {
180
	    if( count($this->coords[1])!=$numpoints )
181
		JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);
182
//("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints");
183
	    else
184
		$exist_x = true;
185
	}
186
	else
187
	    $exist_x = false;
188
 
189
	if( $this->barcenter )
190
	    $textadj = 0.5-$xscale->text_scale_off;
191
	else
192
	    $textadj = 0;
193
 
194
	// Find the first numeric data point
195
	$startpoint=0;
196
	while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) )
197
	    ++$startpoint;
198
 
199
	// Bail out if no data points
200
	if( $startpoint == $numpoints )
201
	    return;
202
 
203
	if( $this->iFastStroke ) {
204
	    $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x);
205
	    return;
206
	}
207
 
208
	if( $exist_x )
209
	    $xs=$this->coords[1][$startpoint];
210
	else
211
	    $xs= $textadj+$startpoint;
212
 
213
	$img->SetStartPoint($xscale->Translate($xs),
214
			    $yscale->Translate($this->coords[0][$startpoint]));
215
 
216
	if( $this->filled ) {
217
	    $min = $yscale->GetMinVal();
218
	    if( $min > 0 || $this->fillFromMin )
219
		$fillmin = $yscale->scale_abs[0];//Translate($min);
220
	    else
221
		$fillmin = $yscale->Translate(0);
222
 
223
	    $cord[$idx++] = $xscale->Translate($xs);
224
	    $cord[$idx++] = $fillmin;
225
	}
226
	$xt = $xscale->Translate($xs);
227
	$yt = $yscale->Translate($this->coords[0][$startpoint]);
228
	$cord[$idx++] = $xt;
229
	$cord[$idx++] = $yt;
230
	$yt_old = $yt;
231
	$xt_old = $xt;
232
	$y_old = $this->coords[0][$startpoint];
233
 
234
	$this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt);
235
 
236
	$img->SetColor($this->color);
237
	$img->SetLineWeight($this->weight);
238
	$img->SetLineStyle($this->line_style);
239
	$pnts=$startpoint+1;
240
	$firstnonumeric = false;
241
	while( $pnts < $numpoints ) {
242
 
243
	    if( $exist_x ) $x=$this->coords[1][$pnts];
244
	    else $x=$pnts+$textadj;
245
	    $xt = $xscale->Translate($x);
246
	    $yt = $yscale->Translate($this->coords[0][$pnts]);
247
 
248
	    $y=$this->coords[0][$pnts];
249
	    if( $this->step_style ) {
250
		// To handle null values within step style we need to record the
251
		// first non numeric value so we know from where to start if the
252
		// non value is '-'.
253
		if( is_numeric($y) ) {
254
		    $firstnonumeric = false;
255
		    if( is_numeric($y_old) ) {
256
			$img->StyleLine($xt_old,$yt_old,$xt,$yt_old);
257
			$img->StyleLine($xt,$yt_old,$xt,$yt);
258
		    }
259
		    elseif( $y_old == '-' ) {
260
			$img->StyleLine($xt_first,$yt_first,$xt,$yt_first);
261
			$img->StyleLine($xt,$yt_first,$xt,$yt);
262
		    }
263
		    else {
264
			$yt_old = $yt;
265
			$xt_old = $xt;
266
		    }
267
		    $cord[$idx++] = $xt;
268
		    $cord[$idx++] = $yt_old;
269
		    $cord[$idx++] = $xt;
270
		    $cord[$idx++] = $yt;
271
		}
272
		elseif( $firstnonumeric==false ) {
273
		    $firstnonumeric = true;
274
		    $yt_first = $yt_old;
275
		    $xt_first = $xt_old;
276
		}
277
	    }
278
	    else {
279
		$tmp1=$y;
280
		$prev=$this->coords[0][$pnts-1];
281
		if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x';
282
		if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x';
283
 
284
		if( is_numeric($y) || (is_string($y) && $y != '-') ) {
285
		    if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) {
286
			$img->StyleLineTo($xt,$yt);
287
		    }
288
		    else {
289
			$img->SetStartPoint($xt,$yt);
290
		    }
291
		}
292
		if( $this->filled && $tmp1 !== '-' ) {
293
		    if( $tmp1 === 'x' ) {
294
			$cord[$idx++] = $cord[$idx-3];
295
			$cord[$idx++] = $fillmin;
296
		    }
297
		    elseif( $prev === 'x' ) {
298
			$cord[$idx++] = $xt;
299
			$cord[$idx++] = $fillmin;
300
			$cord[$idx++] = $xt;
301
			$cord[$idx++] = $yt;
302
		    }
303
		    else {
304
			$cord[$idx++] = $xt;
305
			$cord[$idx++] = $yt;
306
		    }
307
		}
308
		else {
309
		    if( is_numeric($tmp1)  && (is_numeric($prev) || $prev === '-' ) ) {
310
			$cord[$idx++] = $xt;
311
			$cord[$idx++] = $yt;
312
		    }
313
		}
314
	    }
315
	    $yt_old = $yt;
316
	    $xt_old = $xt;
317
	    $y_old = $y;
318
 
319
	    $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);
320
 
321
	    ++$pnts;
322
	}
323
 
324
	if( $this->filled  ) {
325
	    $cord[$idx++] = $xt;
326
	    if( $min > 0 || $this->fillFromMin )
327
		$cord[$idx++] = $yscale->Translate($min);
328
	    else
329
		$cord[$idx++] = $yscale->Translate(0);
330
	    if( $this->fillgrad ) {
331
		$img->SetLineWeight(1);
332
		$grad = new Gradient($img);
333
		$grad->SetNumColors($this->fillgrad_numcolors);
334
		$grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor);
335
		$img->SetLineWeight($this->weight);
336
	    }
337
	    else {
338
		$img->SetColor($this->fill_color);
339
		$img->FilledPolygon($cord);
340
	    }
341
	    if( $this->line_weight > 0 ) {
342
		$img->SetColor($this->color);
343
		$img->Polygon($cord);
344
	    }
345
	}
346
 
347
	if(!empty($this->filledAreas)) {
348
 
349
	    $minY = $yscale->Translate($yscale->GetMinVal());
350
	    $factor = ($this->step_style ? 4 : 2);
351
 
352
	    for($i = 0; $i < sizeof($this->filledAreas); ++$i) {
353
		// go through all filled area elements ordered by insertion
354
		// fill polygon array
355
		$areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];
356
		$areaCoords[] = $minY;
357
 
358
		$areaCoords =
359
		    array_merge($areaCoords,
360
				array_slice($cord,
361
					    $this->filledAreas[$i][0] * $factor,
362
					    ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1))  * $factor));
363
		$areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x
364
		$areaCoords[] = $minY; // last y
365
 
366
		if($this->filledAreas[$i][3]) {
367
		    $img->SetColor($this->filledAreas[$i][2]);
368
		    $img->FilledPolygon($areaCoords);
369
		    $img->SetColor($this->color);
370
		}
371
		// Check if we should draw the frame.
372
		// If not we still re-draw the line since it might have been
373
		// partially overwritten by the filled area and it doesn't look
374
		// very good.
375
		// TODO: The behaviour is undefined if the line does not have
376
		// any line at the position of the area.
377
		if( $this->filledAreas[$i][4] )
378
		    $img->Polygon($areaCoords);
379
		else
380
	    	    $img->Polygon($cord);
381
 
382
		$areaCoords = array();
383
	    }
384
	}
385
 
386
	if( $this->mark->type == -1 || $this->mark->show == false )
387
	    return;
388
 
389
	for( $pnts=0; $pnts<$numpoints; ++$pnts) {
390
 
391
	    if( $exist_x ) $x=$this->coords[1][$pnts];
392
	    else $x=$pnts+$textadj;
393
	    $xt = $xscale->Translate($x);
394
	    $yt = $yscale->Translate($this->coords[0][$pnts]);
395
 
396
	    if( is_numeric($this->coords[0][$pnts]) ) {
397
		if( !empty($this->csimtargets[$pnts]) ) {
398
		    if( !empty($this->csimwintargets[$pnts]) ) {
399
			$this->mark->SetCSIMTarget($this->csimtargets[$pnts],$this->csimwintargets[$pnts]);
400
		    }
401
		    else {
402
			$this->mark->SetCSIMTarget($this->csimtargets[$pnts]);
403
		    }
404
		    $this->mark->SetCSIMAlt($this->csimalts[$pnts]);
405
		}
406
		if( $exist_x )
407
		    $x=$this->coords[1][$pnts];
408
		else
409
		    $x=$pnts;
410
		$this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x);
411
		$this->mark->Stroke($img,$xt,$yt);
412
		$this->csimareas .= $this->mark->GetCSIMAreas();
413
	    }
414
	}
415
 
416
 
417
    }
418
} // Class
419
 
420
 
421
//===================================================
422
// CLASS AccLinePlot
423
// Description:
424
//===================================================
425
class AccLinePlot extends Plot {
426
    var $plots=null,$nbrplots=0,$numpoints=0;
427
    var $iStartEndZero=true;
428
//---------------
429
// CONSTRUCTOR
430
    function AccLinePlot($plots) {
431
        $this->plots = $plots;
432
	$this->nbrplots = count($plots);
433
	$this->numpoints = $plots[0]->numpoints;
434
 
435
	// Verify that all plots have the same number of data points
436
	for( $i=1; $i < $this->nbrplots; ++$i ) {
437
	    if( $plots[$i]->numpoints != $this->numpoints ) {
438
		JpGraphError::RaiseL(10003);//('Each plot in an accumulated lineplot must have the same number of data points',0)
439
	    }
440
	}
441
 
442
	for($i=0; $i < $this->nbrplots; ++$i ) {
443
	    $this->LineInterpolate($this->plots[$i]->coords[0]);
444
	}
445
    }
446
 
447
//---------------
448
// PUBLIC METHODS
449
    function Legend(&$graph) {
450
	$n=count($this->plots);
451
	for($i=0; $i < $n; ++$i )
452
	    $this->plots[$i]->DoLegend($graph);
453
    }
454
 
455
    function Max() {
456
	list($xmax) = $this->plots[0]->Max();
457
	$nmax=0;
458
	$n = count($this->plots);
459
	for($i=0; $i < $n; ++$i) {
460
	    $nc = count($this->plots[$i]->coords[0]);
461
	    $nmax = max($nmax,$nc);
462
	    list($x) = $this->plots[$i]->Max();
463
	    $xmax = Max($xmax,$x);
464
	}
465
	for( $i = 0; $i < $nmax; $i++ ) {
466
	    // Get y-value for line $i by adding the
467
	    // individual bars from all the plots added.
468
	    // It would be wrong to just add the
469
	    // individual plots max y-value since that
470
	    // would in most cases give to large y-value.
471
	    $y=$this->plots[0]->coords[0][$i];
472
	    for( $j = 1; $j < $this->nbrplots; $j++ ) {
473
		$y += $this->plots[ $j ]->coords[0][$i];
474
	    }
475
	    $ymax[$i] = $y;
476
	}
477
	$ymax = max($ymax);
478
	return array($xmax,$ymax);
479
    }
480
 
481
    function Min() {
482
	$nmax=0;
483
	list($xmin,$ysetmin) = $this->plots[0]->Min();
484
	$n = count($this->plots);
485
	for($i=0; $i < $n; ++$i) {
486
	    $nc = count($this->plots[$i]->coords[0]);
487
	    $nmax = max($nmax,$nc);
488
	    list($x,$y) = $this->plots[$i]->Min();
489
	    $xmin = Min($xmin,$x);
490
	    $ysetmin = Min($y,$ysetmin);
491
	}
492
	for( $i = 0; $i < $nmax; $i++ ) {
493
	    // Get y-value for line $i by adding the
494
	    // individual bars from all the plots added.
495
	    // It would be wrong to just add the
496
	    // individual plots min y-value since that
497
	    // would in most cases give to small y-value.
498
	    $y=$this->plots[0]->coords[0][$i];
499
	    for( $j = 1; $j < $this->nbrplots; $j++ ) {
500
		$y += $this->plots[ $j ]->coords[0][$i];
501
	    }
502
	    $ymin[$i] = $y;
503
	}
504
	$ymin = Min($ysetmin,Min($ymin));
505
	return array($xmin,$ymin);
506
    }
507
 
508
    // Gets called before any axis are stroked
509
    function PreStrokeAdjust(&$graph) {
510
 
511
	// If another plot type have already adjusted the
512
	// offset we don't touch it.
513
	// (We check for empty in case the scale is  a log scale
514
	// and hence doesn't contain any xlabel_offset)
515
 
516
	if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||
517
	    $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
518
	    if( $this->center ) {
519
		++$this->numpoints;
520
		$a=0.5; $b=0.5;
521
	    } else {
522
		$a=0; $b=0;
523
	    }
524
	    $graph->xaxis->scale->ticks->SetXLabelOffset($a);
525
	    $graph->SetTextScaleOff($b);
526
	    $graph->xaxis->scale->ticks->SupressMinorTickMarks();
527
	}
528
 
529
    }
530
 
531
    function SetInterpolateMode($aIntMode) {
532
	$this->iStartEndZero=$aIntMode;
533
    }
534
 
535
    // Replace all '-' with an interpolated value. We use straightforward
536
    // linear interpolation. If the data starts with one or several '-' they
537
    // will be replaced by the the first valid data point
538
    function LineInterpolate(&$aData) {
539
 
540
	$n=count($aData);
541
	$i=0;
542
 
543
	// If first point is undefined we will set it to the same as the first
544
	// valid data
545
	if( $aData[$i]==='-' ) {
546
	    // Find the first valid data
547
	    while( $i < $n && $aData[$i]==='-' ) {
548
		++$i;
549
	    }
550
	    if( $i < $n ) {
551
		for($j=0; $j < $i; ++$j ) {
552
		    if( $this->iStartEndZero )
553
			$aData[$i] = 0;
554
		    else
555
			$aData[$j] = $aData[$i];
556
		}
557
	    }
558
	    else {
559
		// All '-' => Error
560
		return false;
561
	    }
562
	}
563
 
564
	while($i < $n) {
565
	    while( $i < $n && $aData[$i] !== '-' ) {
566
		++$i;
567
	    }
568
	    if( $i < $n ) {
569
		$pstart=$i-1;
570
 
571
		// Now see how long this segment of '-' are
572
		while( $i < $n && $aData[$i] === '-' )
573
		    ++$i;
574
		if( $i < $n ) {
575
		    $pend=$i;
576
		    $size=$pend-$pstart;
577
		    $k=($aData[$pend]-$aData[$pstart])/$size;
578
		    // Replace the segment of '-' with a linear interpolated value.
579
		    for($j=1; $j < $size; ++$j ) {
580
			$aData[$pstart+$j] = $aData[$pstart] + $j*$k ;
581
		    }
582
		}
583
		else {
584
		    // There are no valid end point. The '-' goes all the way to the end
585
		    // In that case we just set all the remaining values the the same as the
586
		    // last valid data point.
587
		    for( $j=$pstart+1; $j < $n; ++$j )
588
			if( $this->iStartEndZero )
589
			    $aData[$j] = 0;
590
			else
591
			    $aData[$j] = $aData[$pstart] ;
592
		}
593
	    }
594
	}
595
	return true;
596
    }
597
 
598
 
599
 
600
    // To avoid duplicate of line drawing code here we just
601
    // change the y-values for each plot and then restore it
602
    // after we have made the stroke. We must do this copy since
603
    // it wouldn't be possible to create an acc line plot
604
    // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));
605
    // since this method would have a side effect.
606
    function Stroke(&$img,&$xscale,&$yscale) {
607
	$img->SetLineWeight($this->weight);
608
	$this->numpoints = count($this->plots[0]->coords[0]);
609
	// Allocate array
610
	$coords[$this->nbrplots][$this->numpoints]=0;
611
	for($i=0; $i<$this->numpoints; $i++) {
612
	    $coords[0][$i]=$this->plots[0]->coords[0][$i];
613
	    $accy=$coords[0][$i];
614
	    for($j=1; $j<$this->nbrplots; ++$j ) {
615
		$coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy;
616
		$accy = $coords[$j][$i];
617
	    }
618
	}
619
	for($j=$this->nbrplots-1; $j>=0; --$j) {
620
	    $p=$this->plots[$j];
621
	    for( $i=0; $i<$this->numpoints; ++$i) {
622
		$tmp[$i]=$p->coords[0][$i];
623
		$p->coords[0][$i]=$coords[$j][$i];
624
	    }
625
	    $p->Stroke($img,$xscale,$yscale);
626
	    for( $i=0; $i<$this->numpoints; ++$i)
627
		$p->coords[0][$i]=$tmp[$i];
628
	    $p->coords[0][]=$tmp;
629
	}
630
    }
631
} // Class
632
 
633
 
634
/* EOF */
635
?>