Subversion Repositories Applications.papyrus

Rev

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

Rev Author Line No. Line
2150 mathias 1
<?php
2
//=======================================================================
3
// File:	JPGRAPH_PLOTBAND.PHP
4
// Description:	PHP4 Graph Plotting library. Extension module.
5
// Created: 	2004-02-18
6
// Ver:		$Id: jpgraph_plotband.php 781 2006-10-08 08:07:47Z ljp $
7
//
8
// Copyright (c) Aditus Consulting. All rights reserved.
9
//========================================================================
10
 
11
// Constants for types of static bands in plot area
12
DEFINE("BAND_RDIAG",1);	// Right diagonal lines
13
DEFINE("BAND_LDIAG",2); // Left diagonal lines
14
DEFINE("BAND_SOLID",3); // Solid one color
15
DEFINE("BAND_VLINE",4); // Vertical lines
16
DEFINE("BAND_HLINE",5);  // Horizontal lines
17
DEFINE("BAND_3DPLANE",6);  // "3D" Plane
18
DEFINE("BAND_HVCROSS",7);  // Vertical/Hor crosses
19
DEFINE("BAND_DIAGCROSS",8); // Diagonal crosses
20
 
21
 
22
// Utility class to hold coordinates for a rectangle
23
class Rectangle {
24
    public $x,$y,$w,$h;
25
    public $xe, $ye;
26
    function Rectangle($aX,$aY,$aWidth,$aHeight) {
27
	$this->x=$aX;
28
	$this->y=$aY;
29
	$this->w=$aWidth;
30
	$this->h=$aHeight;
31
	$this->xe=$aX+$aWidth-1;
32
	$this->ye=$aY+$aHeight-1;
33
    }
34
}
35
 
36
//=====================================================================
37
// Class RectPattern
38
// Base class for pattern hierarchi that is used to display patterned
39
// bands on the graph. Any subclass that doesn't override Stroke()
40
// must at least implement method DoPattern($aImg) which is responsible
41
// for drawing the pattern onto the graph.
42
//=====================================================================
43
class RectPattern {
44
    protected $color;
45
    protected $weight;
46
    protected $rect=null;
47
    protected $doframe=true;
48
    protected $linespacing;	// Line spacing in pixels
49
    protected $iBackgroundColor=-1;  // Default is no background fill
50
 
51
    function RectPattern($aColor,$aWeight=1) {
52
	$this->color = $aColor;
53
	$this->weight = $aWeight;
54
    }
55
 
56
    function SetBackground($aBackgroundColor) {
57
	$this->iBackgroundColor=$aBackgroundColor;
58
    }
59
 
60
    function SetPos($aRect) {
61
	$this->rect = $aRect;
62
    }
63
 
64
    function ShowFrame($aShow=true) {
65
	$this->doframe=$aShow;
66
    }
67
 
68
    function SetDensity($aDens) {
69
	if( $aDens < 1 || $aDens > 100 )
70
	    JpGraphError::RaiseL(16001,$aDens);
71
//(" Desity for pattern must be between 1 and 100. (You tried $aDens)");
72
	// 1% corresponds to linespacing=50
73
	// 100 % corresponds to linespacing 1
74
	$this->linespacing = floor(((100-$aDens)/100.0)*50)+1;
75
 
76
    }
77
 
78
    function Stroke($aImg) {
79
	if( $this->rect == null )
80
	    JpGraphError::RaiseL(16002);
81
//(" No positions specified for pattern.");
82
 
83
	if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) {
84
	    $aImg->SetColor($this->iBackgroundColor);
85
	    $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye);
86
	}
87
 
88
	$aImg->SetColor($this->color);
89
	$aImg->SetLineWeight($this->weight);
90
 
91
	// Virtual function implemented by subclass
92
	$this->DoPattern($aImg);
93
 
94
	// Frame around the pattern area
95
	if( $this->doframe )
96
	    $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye);
97
    }
98
 
99
}
100
 
101
 
102
//=====================================================================
103
// Class RectPatternSolid
104
// Implements a solid band
105
//=====================================================================
106
class RectPatternSolid extends RectPattern {
107
 
108
    function RectPatternSolid($aColor="black",$aWeight=1) {
109
	parent::RectPattern($aColor,$aWeight);
110
    }
111
 
112
    function DoPattern($aImg) {
113
	$aImg->SetColor($this->color);
114
	$aImg->FilledRectangle($this->rect->x,$this->rect->y,
115
			       $this->rect->xe,$this->rect->ye);
116
    }
117
}
118
 
119
//=====================================================================
120
// Class RectPatternHor
121
// Implements horizontal line pattern
122
//=====================================================================
123
class RectPatternHor extends RectPattern {
124
 
125
    function RectPatternHor($aColor="black",$aWeight=1,$aLineSpacing=7) {
126
	parent::RectPattern($aColor,$aWeight);
127
	$this->linespacing = $aLineSpacing;
128
    }
129
 
130
    function DoPattern($aImg) {
131
	$x0 = $this->rect->x;
132
	$x1 = $this->rect->xe;
133
	$y = $this->rect->y;
134
	while( $y < $this->rect->ye ) {
135
	    $aImg->Line($x0,$y,$x1,$y);
136
	    $y += $this->linespacing;
137
	}
138
    }
139
}
140
 
141
//=====================================================================
142
// Class RectPatternVert
143
// Implements vertical line pattern
144
//=====================================================================
145
class RectPatternVert extends RectPattern {
146
 
147
    function RectPatternVert($aColor="black",$aWeight=1,$aLineSpacing=7) {
148
	parent::RectPattern($aColor,$aWeight);
149
	$this->linespacing = $aLineSpacing;
150
    }
151
 
152
    //--------------------
153
    // Private methods
154
    //
155
    function DoPattern($aImg) {
156
	$x = $this->rect->x;
157
	$y0 = $this->rect->y;
158
	$y1 = $this->rect->ye;
159
	while( $x < $this->rect->xe ) {
160
	    $aImg->Line($x,$y0,$x,$y1);
161
	    $x += $this->linespacing;
162
	}
163
    }
164
}
165
 
166
 
167
//=====================================================================
168
// Class RectPatternRDiag
169
// Implements right diagonal pattern
170
//=====================================================================
171
class RectPatternRDiag extends RectPattern {
172
 
173
    function RectPatternRDiag($aColor="black",$aWeight=1,$aLineSpacing=12) {
174
	parent::RectPattern($aColor,$aWeight);
175
	$this->linespacing = $aLineSpacing;
176
    }
177
 
178
    function DoPattern($aImg) {
179
	//  --------------------
180
	//  | /   /   /   /   /|
181
	//  |/   /   /   /   / |
182
	//  |   /   /   /   /  |
183
	//  --------------------
184
	$xe = $this->rect->xe;
185
	$ye = $this->rect->ye;
186
	$x0 = $this->rect->x + round($this->linespacing/2);
187
	$y0 = $this->rect->y;
188
	$x1 = $this->rect->x;
189
	$y1 = $this->rect->y + round($this->linespacing/2);
190
 
191
	while($x0<=$xe && $y1<=$ye) {
192
	    $aImg->Line($x0,$y0,$x1,$y1);
193
	    $x0 += $this->linespacing;
194
	    $y1 += $this->linespacing;
195
	}
196
 
197
	if( $xe-$x1 > $ye-$y0 ) {
198
	    // Width larger than height
199
	    $x1 = $this->rect->x + ($y1-$ye);
200
	    $y1 = $ye;
201
	    $y0 = $this->rect->y;
202
	    while( $x0 <= $xe ) {
203
		$aImg->Line($x0,$y0,$x1,$y1);
204
		$x0 += $this->linespacing;
205
		$x1 += $this->linespacing;
206
	    }
207
 
208
	    $y0=$this->rect->y + ($x0-$xe);
209
	    $x0=$xe;
210
	}
211
	else {
212
	    // Height larger than width
213
	    $diff = $x0-$xe;
214
	    $y0 = $diff+$this->rect->y;
215
	    $x0 = $xe;
216
	    $x1 = $this->rect->x;
217
	    while( $y1 <= $ye ) {
218
		$aImg->Line($x0,$y0,$x1,$y1);
219
		$y1 += $this->linespacing;
220
		$y0 += $this->linespacing;
221
	    }
222
 
223
	    $diff = $y1-$ye;
224
	    $y1 = $ye;
225
	    $x1 = $diff + $this->rect->x;
226
	}
227
 
228
	while( $y0 <= $ye ) {
229
	    $aImg->Line($x0,$y0,$x1,$y1);
230
	    $y0 += $this->linespacing;
231
	    $x1 += $this->linespacing;
232
	}
233
    }
234
}
235
 
236
//=====================================================================
237
// Class RectPatternLDiag
238
// Implements left diagonal pattern
239
//=====================================================================
240
class RectPatternLDiag extends RectPattern {
241
 
242
    function RectPatternLDiag($aColor="black",$aWeight=1,$aLineSpacing=12) {
243
	$this->linespacing = $aLineSpacing;
244
	parent::RectPattern($aColor,$aWeight);
245
    }
246
 
247
    function DoPattern($aImg) {
248
	//  --------------------
249
	//  |\   \   \   \   \ |
250
	//  | \   \   \   \   \|
251
	//  |  \   \   \   \   |
252
	//  |------------------|
253
	$xe = $this->rect->xe;
254
	$ye = $this->rect->ye;
255
	$x0 = $this->rect->x + round($this->linespacing/2);
256
	$y0 = $this->rect->ye;
257
	$x1 = $this->rect->x;
258
	$y1 = $this->rect->ye - round($this->linespacing/2);
259
 
260
	while($x0<=$xe && $y1>=$this->rect->y) {
261
	    $aImg->Line($x0,$y0,$x1,$y1);
262
	    $x0 += $this->linespacing;
263
	    $y1 -= $this->linespacing;
264
	}
265
	if( $xe-$x1 > $ye-$this->rect->y ) {
266
	    // Width larger than height
267
	    $x1 = $this->rect->x + ($this->rect->y-$y1);
268
	    $y0=$ye; $y1=$this->rect->y;
269
	    while( $x0 <= $xe ) {
270
		$aImg->Line($x0,$y0,$x1,$y1);
271
		$x0 += $this->linespacing;
272
		$x1 += $this->linespacing;
273
	    }
274
 
275
	    $y0=$this->rect->ye - ($x0-$xe);
276
	    $x0=$xe;
277
	}
278
	else {
279
	    // Height larger than width
280
	    $diff = $x0-$xe;
281
	    $y0 = $ye-$diff;
282
	    $x0 = $xe;
283
	    while( $y1 >= $this->rect->y ) {
284
		$aImg->Line($x0,$y0,$x1,$y1);
285
		$y0 -= $this->linespacing;
286
		$y1 -= $this->linespacing;
287
	    }
288
	    $diff = $this->rect->y - $y1;
289
	    $x1 = $this->rect->x + $diff;
290
	    $y1 = $this->rect->y;
291
	}
292
	while( $y0 >= $this->rect->y ) {
293
	    $aImg->Line($x0,$y0,$x1,$y1);
294
	    $y0 -= $this->linespacing;
295
	    $x1 += $this->linespacing;
296
	}
297
    }
298
}
299
 
300
//=====================================================================
301
// Class RectPattern3DPlane
302
// Implements "3D" plane pattern
303
//=====================================================================
304
class RectPattern3DPlane extends RectPattern {
305
    private $alpha=50;  // Parameter that specifies the distance
306
    // to "simulated" horizon in pixel from the
307
    // top of the band. Specifies how fast the lines
308
    // converge.
309
 
310
    function RectPattern3DPlane($aColor="black",$aWeight=1) {
311
	parent::RectPattern($aColor,$aWeight);
312
	$this->SetDensity(10);  // Slightly larger default
313
    }
314
 
315
    function SetHorizon($aHorizon) {
316
	$this->alpha=$aHorizon;
317
    }
318
 
319
    function DoPattern($aImg) {
320
	// "Fake" a nice 3D grid-effect.
321
	$x0 = $this->rect->x + $this->rect->w/2;
322
	$y0 = $this->rect->y;
323
	$x1 = $x0;
324
	$y1 = $this->rect->ye;
325
	$x0_right = $x0;
326
	$x1_right = $x1;
327
 
328
	// BTW "apa" means monkey in Swedish but is really a shortform for
329
	// "alpha+a" which was the labels I used on paper when I derived the
330
	// geometric to get the 3D perspective right.
331
	// $apa is the height of the bounding rectangle plus the distance to the
332
	// artifical horizon (alpha)
333
	$apa = $this->rect->h + $this->alpha;
334
 
335
	// Three cases and three loops
336
	// 1) The endpoint of the line ends on the bottom line
337
	// 2) The endpoint ends on the side
338
	// 3) Horizontal lines
339
 
340
	// Endpoint falls on bottom line
341
	$middle=$this->rect->x + $this->rect->w/2;
342
	$dist=$this->linespacing;
343
	$factor=$this->alpha /($apa);
344
	while($x1>$this->rect->x) {
345
	    $aImg->Line($x0,$y0,$x1,$y1);
346
	    $aImg->Line($x0_right,$y0,$x1_right,$y1);
347
	    $x1 = $middle - $dist;
348
	    $x0 = $middle - $dist * $factor;
349
	    $x1_right = $middle + $dist;
350
	    $x0_right =  $middle + $dist * $factor;
351
	    $dist += $this->linespacing;
352
	}
353
 
354
	// Endpoint falls on sides
355
	$dist -= $this->linespacing;
356
	$d=$this->rect->w/2;
357
	$c = $apa - $d*$apa/$dist;
358
	while( $x0>$this->rect->x ) {
359
	    $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c);
360
	    $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c);
361
	    $dist += $this->linespacing;
362
	    $x0 = $middle - $dist * $factor;
363
	    $x1 = $middle - $dist;
364
	    $x0_right =  $middle + $dist * $factor;
365
	    $c = $apa - $d*$apa/$dist;
366
	}
367
 
368
	// Horizontal lines
369
	// They need some serious consideration since they are a function
370
	// of perspective depth (alpha) and density (linespacing)
371
	$x0=$this->rect->x;
372
	$x1=$this->rect->xe;
373
	$y=$this->rect->ye;
374
 
375
	// The first line is drawn directly. Makes the loop below slightly
376
	// more readable.
377
	$aImg->Line($x0,$y,$x1,$y);
378
	$hls = $this->linespacing;
379
 
380
	// A correction factor for vertical "brick" line spacing to account for
381
	// a) the difference in number of pixels hor vs vert
382
	// b) visual apperance to make the first layer of "bricks" look more
383
	// square.
384
	$vls = $this->linespacing*0.6;
385
 
386
	$ds = $hls*($apa-$vls)/$apa;
387
	// Get the slope for the "perspective line" going from bottom right
388
	// corner to top left corner of the "first" brick.
389
 
390
	// Uncomment the following lines if you want to get a visual understanding
391
	// of what this helpline does. BTW this mimics the way you would get the
392
	// perspective right when drawing on paper.
393
	/*
394
	  $x0 = $middle;
395
	  $y0 = $this->rect->ye;
396
	  $len=floor(($this->rect->ye-$this->rect->y)/$vls);
397
	  $x1 = $middle+round($len*$ds);
398
	  $y1 = $this->rect->ye-$len*$vls;
399
	  $aImg->PushColor("red");
400
	  $aImg->Line($x0,$y0,$x1,$y1);
401
	  $aImg->PopColor();
402
	*/
403
 
404
	$y -= $vls;
405
	$k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds));
406
	$dist = $hls;
407
	while( $y>$this->rect->y ) {
408
	    $aImg->Line($this->rect->x,$y,$this->rect->xe,$y);
409
	    $adj = $k*$dist/(1+$dist*$k/$apa);
410
	    if( $adj < 2 ) $adj=1;
411
	    $y = $this->rect->ye - round($adj);
412
	    $dist += $hls;
413
	}
414
    }
415
}
416
 
417
//=====================================================================
418
// Class RectPatternCross
419
// Vert/Hor crosses
420
//=====================================================================
421
class RectPatternCross extends RectPattern {
422
    private $vert=null;
423
    private $hor=null;
424
    function RectPatternCross($aColor="black",$aWeight=1) {
425
	parent::RectPattern($aColor,$aWeight);
426
	$this->vert = new RectPatternVert($aColor,$aWeight);
427
	$this->hor  = new RectPatternHor($aColor,$aWeight);
428
    }
429
 
430
    function SetOrder($aDepth) {
431
	$this->vert->SetOrder($aDepth);
432
	$this->hor->SetOrder($aDepth);
433
    }
434
 
435
    function SetPos($aRect) {
436
	parent::SetPos($aRect);
437
	$this->vert->SetPos($aRect);
438
	$this->hor->SetPos($aRect);
439
    }
440
 
441
    function SetDensity($aDens) {
442
	$this->vert->SetDensity($aDens);
443
	$this->hor->SetDensity($aDens);
444
    }
445
 
446
    function DoPattern($aImg) {
447
	$this->vert->DoPattern($aImg);
448
	$this->hor->DoPattern($aImg);
449
    }
450
}
451
 
452
//=====================================================================
453
// Class RectPatternDiagCross
454
// Vert/Hor crosses
455
//=====================================================================
456
 
457
class RectPatternDiagCross extends RectPattern {
458
    private $left=null;
459
    private $right=null;
460
    function RectPatternDiagCross($aColor="black",$aWeight=1) {
461
	parent::RectPattern($aColor,$aWeight);
462
	$this->right = new RectPatternRDiag($aColor,$aWeight);
463
	$this->left  = new RectPatternLDiag($aColor,$aWeight);
464
    }
465
 
466
    function SetOrder($aDepth) {
467
	$this->left->SetOrder($aDepth);
468
	$this->right->SetOrder($aDepth);
469
    }
470
 
471
    function SetPos($aRect) {
472
	parent::SetPos($aRect);
473
	$this->left->SetPos($aRect);
474
	$this->right->SetPos($aRect);
475
    }
476
 
477
    function SetDensity($aDens) {
478
	$this->left->SetDensity($aDens);
479
	$this->right->SetDensity($aDens);
480
    }
481
 
482
    function DoPattern($aImg) {
483
	$this->left->DoPattern($aImg);
484
	$this->right->DoPattern($aImg);
485
    }
486
 
487
}
488
 
489
//=====================================================================
490
// Class RectPatternFactory
491
// Factory class for rectangular pattern
492
//=====================================================================
493
class RectPatternFactory {
494
    function RectPatternFactory() {
495
	// Empty
496
    }
497
    function Create($aPattern,$aColor,$aWeight=1) {
498
	switch($aPattern) {
499
	    case BAND_RDIAG:
500
		$obj =  new RectPatternRDiag($aColor,$aWeight);
501
		break;
502
	    case BAND_LDIAG:
503
		$obj =  new RectPatternLDiag($aColor,$aWeight);
504
		break;
505
	    case BAND_SOLID:
506
		$obj =  new RectPatternSolid($aColor,$aWeight);
507
		break;
508
	    case BAND_VLINE:
509
		$obj =  new RectPatternVert($aColor,$aWeight);
510
		break;
511
	    case BAND_HLINE:
512
		$obj =  new RectPatternHor($aColor,$aWeight);
513
		break;
514
	    case BAND_3DPLANE:
515
		$obj =  new RectPattern3DPlane($aColor,$aWeight);
516
		break;
517
	    case BAND_HVCROSS:
518
		$obj =  new RectPatternCross($aColor,$aWeight);
519
		break;
520
	    case BAND_DIAGCROSS:
521
		$obj =  new RectPatternDiagCross($aColor,$aWeight);
522
		break;
523
	    default:
524
		JpGraphError::RaiseL(16003,$aPattern);
525
//(" Unknown pattern specification ($aPattern)");
526
	}
527
	return $obj;
528
    }
529
}
530
 
531
 
532
//=====================================================================
533
// Class PlotBand
534
// Factory class which is used by the client.
535
// It is responsible for factoring the corresponding pattern
536
// concrete class.
537
//=====================================================================
538
class PlotBand {
539
    public $depth; // Determine if band should be over or under the plots
540
    private $prect=null;
541
    private $dir, $min, $max;
542
 
543
    function PlotBand($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) {
544
	$f =  new RectPatternFactory();
545
	$this->prect = $f->Create($aPattern,$aColor,$aWeight);
546
	if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) )
547
	    JpGraphError::RaiseL(16004);
548
//('Min value for plotband is larger than specified max value. Please correct.');
549
	$this->dir = $aDir;
550
	$this->min = $aMin;
551
	$this->max = $aMax;
552
	$this->depth=$aDepth;
553
    }
554
 
555
    // Set position. aRect contains absolute image coordinates
556
    function SetPos($aRect) {
557
	assert( $this->prect != null ) ;
558
	$this->prect->SetPos($aRect);
559
    }
560
 
561
    function ShowFrame($aFlag=true) {
562
	$this->prect->ShowFrame($aFlag);
563
    }
564
 
565
    // Set z-order. In front of pplot or in the back
566
    function SetOrder($aDepth) {
567
	$this->depth=$aDepth;
568
    }
569
 
570
    function SetDensity($aDens) {
571
	$this->prect->SetDensity($aDens);
572
    }
573
 
574
    function GetDir() {
575
	return $this->dir;
576
    }
577
 
578
    function GetMin() {
579
	return $this->min;
580
    }
581
 
582
    function GetMax() {
583
	return $this->max;
584
    }
585
 
586
    function PreStrokeAdjust($aGraph) {
587
	// Nothing to do
588
    }
589
 
590
    // Display band
591
    function Stroke($aImg,$aXScale,$aYScale) {
592
	assert( $this->prect != null ) ;
593
	if( $this->dir == HORIZONTAL ) {
594
	    if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal();
595
	    if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal();
596
 
597
            // Only draw the bar if it actually appears in the range
598
            if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) {
599
 
600
	    // Trucate to limit of axis
601
	    $this->min = max($this->min, $aYScale->GetMinVal());
602
	    $this->max = min($this->max, $aYScale->GetMaxVal());
603
 
604
	    $x=$aXScale->scale_abs[0];
605
	    $y=$aYScale->Translate($this->max);
606
	    $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1;
607
	    $height=abs($y-$aYScale->Translate($this->min))+1;
608
	    $this->prect->SetPos(new Rectangle($x,$y,$width,$height));
609
	    $this->prect->Stroke($aImg);
610
            }
611
	}
612
	else {	// VERTICAL
613
	    if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal();
614
	    if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal();
615
 
616
            // Only draw the bar if it actually appears in the range
617
	    if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) {
618
 
619
	    // Trucate to limit of axis
620
	    $this->min = max($this->min, $aXScale->GetMinVal());
621
	    $this->max = min($this->max, $aXScale->GetMaxVal());
622
 
623
	    $y=$aYScale->scale_abs[1];
624
	    $x=$aXScale->Translate($this->min);
625
	    $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]);
626
	    $width=abs($x-$aXScale->Translate($this->max));
627
	    $this->prect->SetPos(new Rectangle($x,$y,$width,$height));
628
	    $this->prect->Stroke($aImg);
629
            }
630
	}
631
    }
632
}
633
 
634
 
635
?>