WindrosePlot::SetRadialWeights()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * JPGraph v4.0.3
5
 */
6
7
namespace Amenadiel\JpGraph\Plot;
8
9
use Amenadiel\JpGraph\Graph;
10
use Amenadiel\JpGraph\Image;
11
use Amenadiel\JpGraph\Text;
12
use Amenadiel\JpGraph\Util;
13
14
define('WINDROSE_TYPE4', 1);
15
define('WINDROSE_TYPE8', 2);
16
define('WINDROSE_TYPE16', 3);
17
define('WINDROSE_TYPEFREE', 4);
18
19
/*
20
 * How should the labels for the circular grids be aligned
21
 */
22
define('LBLALIGN_CENTER', 1);
23
define('LBLALIGN_TOP', 2);
24
25
/*
26
 * How should the labels around the plot be align
27
 */
28
define('LBLPOSITION_CENTER', 1);
29
define('LBLPOSITION_EDGE', 2);
30
31
/*
32
 * Interpretation of ordinal values in the data
33
 */
34
define('KEYENCODING_CLOCKWISE', 1);
35
define('KEYENCODING_ANTICLOCKWISE', 2);
36
37
// Internal debug flag
38
define('__DEBUG', false);
39
define('RANGE_OVERLAPPING', 0);
40
define('RANGE_DISCRETE', 1);
41
42
/**
43
 * @class WindrosePlot
44
 */
45
class WindrosePlot
46
{
47
    private $iAntiAlias          = true;
48
    private $iData               = [];
49
    public $iX                   = 0.5;
50
    public $iY                   = 0.5;
51
    public $iSize                = 0.55;
52
    private $iGridColor1         = 'gray';
53
    private $iGridColor2         = 'darkgreen';
54
    private $iRadialColorArray   = [];
55
    private $iRadialWeightArray  = [];
56
    private $iRadialStyleArray   = [];
57
    private $iRanges             = [1, 2, 3, 5, 6, 10, 13.5, 99.0];
58
    private $iRangeStyle         = RANGE_OVERLAPPING;
59
    public $iCenterSize          = 60;
60
    private $iType               = WINDROSE_TYPE16;
61
    public $iFontFamily          = FF_VERDANA;
62
    public $iFontStyle           = FS_NORMAL;
63
    public $iFontSize            = 10;
64
    public $iFontColor           = 'darkgray';
65
    private $iRadialGridStyle    = 'longdashed';
66
    private $iAllDirectionLabels = ['E', 'ENE', 'NE', 'NNE', 'N', 'NNW', 'NW', 'WNW', 'W', 'WSW', 'SW', 'SSW', 'S', 'SSE', 'SE', 'ESE'];
67
    private $iStandardDirections = [];
68
    private $iCircGridWeight     = 3;
69
    private $iRadialGridWeight   = 1;
70
    private $iLabelMargin        = 12;
71
    private $iLegweights         = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
72
    private $iLegColors          = ['orange', 'black', 'blue', 'red', 'green', 'purple', 'navy', 'yellow', 'brown'];
73
    private $iLabelFormatString  = '';
74
    private $iLabels             = [];
75
    private $iLabelPositioning   = LBLPOSITION_EDGE;
76
    private $iColor              = 'white';
77
    private $iShowBox            = false;
78
    private $iBoxColor           = 'black';
79
    private $iBoxWeight          = 1;
80
    private $iBoxStyle           = 'solid';
81
    private $iOrdinalEncoding    = KEYENCODING_ANTICLOCKWISE;
82
    public $legend;
83
84
    public function __construct($aData)
85
    {
86
        $this->iData  = $aData;
87
        $this->legend = new LegendStyle();
88
89
        // Setup the scale
90
        $this->scale = new Graph\WindrosePlotScale($this->iData);
91
92
        // default label for free type i agle and a degree sign
93
        $this->iLabelFormatString = '%.1f' . Graph\SymChar::Get('degree');
94
95
        $delta = 2 * M_PI / 16;
96
        for ($i = 0, $a = 0; $i < 16; ++$i, $a += $delta) {
97
            $this->iStandardDirections[$this->iAllDirectionLabels[$i]] = $a;
98
        }
99
    }
100
101
    // Dummy method to make window plots have the same signature as the
102
    // layout classes since windrose plots are "leaf" classes in the hierarchy
103
    public function LayoutSize()
104
    {
105
        return 1;
106
    }
107
108
    public function SetSize($aSize)
109
    {
110
        $this->iSize = $aSize;
111
    }
112
113
    public function SetDataKeyEncoding($aEncoding)
114
    {
115
        $this->iOrdinalEncoding = $aEncoding;
116
    }
117
118
    public function SetColor($aColor)
119
    {
120
        $this->iColor = $aColor;
121
    }
122
123
    public function SetRadialColors($aColors)
124
    {
125
        $this->iRadialColorArray = $aColors;
126
    }
127
128
    public function SetRadialWeights($aWeights)
129
    {
130
        $this->iRadialWeightArray = $aWeights;
131
    }
132
133
    public function SetRadialStyles($aStyles)
134
    {
135
        $this->iRadialStyleArray = $aStyles;
136
    }
137
138
    public function SetBox($aColor = 'black', $aWeight = 1, $aStyle = 'solid', $aShow = true)
139
    {
140
        $this->iShowBox   = $aShow;
141
        $this->iBoxColor  = $aColor;
142
        $this->iBoxWeight = $aWeight;
143
        $this->iBoxStyle  = $aStyle;
144
    }
145
146
    public function SetLabels($aLabels)
147
    {
148
        $this->iLabels = $aLabels;
149
    }
150
151
    public function SetLabelMargin($aMarg)
152
    {
153
        $this->iLabelMargin = $aMarg;
154
    }
155
156
    public function SetLabelFormat($aLblFormat)
157
    {
158
        $this->iLabelFormatString = $aLblFormat;
159
    }
160
161
    public function SetCompassLabels($aLabels)
162
    {
163
        if (safe_count($aLabels) != 16) {
164
            Util\JpGraphError::RaiseL(22004); //('Label specification for windrose directions must have 16 values (one for each compass direction).');
165
        }
166
        $this->iAllDirectionLabels = $aLabels;
167
168
        $delta = 2 * M_PI / 16;
169
        for ($i = 0, $a = 0; $i < 16; ++$i, $a += $delta) {
170
            $this->iStandardDirections[$this->iAllDirectionLabels[$i]] = $a;
171
        }
172
    }
173
174
    public function SetCenterSize($aSize)
175
    {
176
        $this->iCenterSize = $aSize;
177
    }
178
179
    // Alias for SetCenterSize
180
    public function SetZCircleSize($aSize)
181
    {
182
        $this->iCenterSize = $aSize;
183
    }
184
185
    public function SetFont($aFFam, $aFStyle = FS_NORMAL, $aFSize = 10)
186
    {
187
        $this->iFontFamily = $aFFam;
188
        $this->iFontStyle  = $aFStyle;
189
        $this->iFontSize   = $aFSize;
190
    }
191
192
    public function SetFontColor($aColor)
193
    {
194
        $this->iFontColor = $aColor;
195
    }
196
197
    public function SetGridColor($aColor1, $aColor2)
198
    {
199
        $this->iGridColor1 = $aColor1;
200
        $this->iGridColor2 = $aColor2;
201
    }
202
203
    public function SetGridWeight($aGrid1 = 1, $aGrid2 = 2)
204
    {
205
        $this->iCircGridWeight   = $aGrid1;
206
        $this->iRadialGridWeight = $aGrid2;
207
    }
208
209
    public function SetRadialGridStyle($aStyle)
210
    {
211
        $aStyle = strtolower($aStyle);
212
        if (!in_array($aStyle, ['solid', 'dotted', 'dashed', 'longdashed'], true)) {
213
            Util\JpGraphError::RaiseL(22005); //("Line style for radial lines must be on of ('solid','dotted','dashed','longdashed') ");
214
        }
215
        $this->iRadialGridStyle = $aStyle;
216
    }
217
218
    public function SetRanges($aRanges)
219
    {
220
        $this->iRanges = $aRanges;
221
    }
222
223
    public function SetRangeStyle($aStyle)
224
    {
225
        $this->iRangeStyle = $aStyle;
226
    }
227
228
    public function SetRangeColors($aLegColors)
229
    {
230
        $this->iLegColors = $aLegColors;
231
    }
232
233
    public function SetRangeWeights($aWeights)
234
    {
235
        $n = safe_count($aWeights);
236
        for ($i = 0; $i < $n; ++$i) {
237
            $aWeights[$i] = floor($aWeights[$i] / 2);
238
        }
239
        $this->iLegweights = $aWeights;
240
    }
241
242
    public function SetType($aType)
243
    {
244
        if ($aType < WINDROSE_TYPE4 || $aType > WINDROSE_TYPEFREE) {
245
            Util\JpGraphError::RaiseL(22006); //('Illegal windrose type specified.');
246
        }
247
        $this->iType = $aType;
248
    }
249
250
    // Alias for SetPos()
251
    public function SetCenterPos($aX, $aY)
252
    {
253
        $this->iX = $aX;
254
        $this->iY = $aY;
255
    }
256
257
    public function SetPos($aX, $aY)
258
    {
259
        $this->iX = $aX;
260
        $this->iY = $aY;
261
    }
262
263
    public function SetAntiAlias($aFlag)
264
    {
265
        $this->iAntiAlias = $aFlag;
266
        if (!$aFlag) {
267
            $this->iCircGridWeight = 1;
268
        }
269
    }
270
271
    public function _ThickCircle($aImg, $aXC, $aYC, $aRad, $aWeight, $aColor)
272
    {
273
        $aImg->SetColor($aColor);
274
        $aRad *= 2;
275
        $aImg->Ellipse($aXC, $aYC, $aRad, $aRad);
276
        if ($aWeight > 1) {
277
            $aImg->Ellipse($aXC, $aYC, $aRad + 1, $aRad + 1);
278
            $aImg->Ellipse($aXC, $aYC, $aRad + 2, $aRad + 2);
279
            if ($aWeight > 2) {
280
                $aImg->Ellipse($aXC, $aYC, $aRad + 3, $aRad + 3);
281
                $aImg->Ellipse($aXC, $aYC, $aRad + 3, $aRad + 4);
282
                $aImg->Ellipse($aXC, $aYC, $aRad + 4, $aRad + 3);
283
            }
284
        }
285
    }
286
287
    public function _StrokeWindLeg($aImg, $xc, $yc, $a, $ri, $r, $weight, $color)
288
    {
289
        // If less than 1 px long then we assume this has been caused by rounding problems
290
        // and should not be stroked
291
        if ($r < 1) {
292
            return;
293
        }
294
295
        $xt  = $xc + cos($a) * $ri;
296
        $yt  = $yc - sin($a) * $ri;
297
        $xxt = $xc + cos($a) * ($ri + $r);
298
        $yyt = $yc - sin($a) * ($ri + $r);
299
300
        $x1 = $xt - $weight * sin($a);
301
        $y1 = $yt - $weight * cos($a);
302
        $x2 = $xxt - $weight * sin($a);
303
        $y2 = $yyt - $weight * cos($a);
304
305
        $x3 = $xxt + $weight * sin($a);
306
        $y3 = $yyt + $weight * cos($a);
307
        $x4 = $xt + $weight * sin($a);
308
        $y4 = $yt + $weight * cos($a);
309
310
        $pts = [$x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4];
311
        $aImg->SetColor($color);
312
        $aImg->FilledPolygon($pts);
313
    }
314
315
    public function _StrokeLegend($aImg, $x, $y, $scaling = 1, $aReturnWidth = false)
316
    {
317
        if (!$this->legend->iShow) {
318
            return 0;
319
        }
320
321
        $nlc = safe_count($this->iLegColors);
322
        $nlw = safe_count($this->iLegweights);
323
324
        // Setup font for ranges
325
        $value = new Text\Text();
326
        $value->SetAlign('center', 'bottom');
327
        $value->SetFont(
328
            $this->legend->iLblFontFamily,
329
            $this->legend->iLblFontStyle,
330
            $this->legend->iLblFontSize * $scaling
331
        );
332
        $value->SetColor($this->legend->iLblFontColor);
333
334
        // Remember x-center
335
        $xcenter = $x;
336
337
        // Construct format string
338
        $fmt = $this->legend->iFormatString . '-' . $this->legend->iFormatString;
339
340
        // Make sure that the length of each range is enough to cover the
341
        // size of the labels
342
        $tst = sprintf($fmt, $this->iRanges[0], $this->iRanges[1]);
343
        $value->Set($tst);
344
        $w = $value->GetWidth($aImg);
345
        $l = round(max($this->legend->iLength * $scaling, $w * 1.5));
346
347
        $r   = $this->legend->iCircleRadius * $scaling;
348
        $len = 2 * $r + $this->scale->iMaxNum * $l;
349
350
        // We are called just to find out the width
351
        if ($aReturnWidth) {
352
            return $len;
353
        }
354
355
        $x -= round($len / 2);
356
        $x += $r;
357
358
        // 4 pixels extra vertical margin since the circle sometimes is +/- 1 pixel of the
359
        // theorethical radius due to imperfection in the GD library
360
        //$y -= round(max($r,$scaling*$this->iLegweights[($this->scale->iMaxNum-1) % $nlw])+4*$scaling);
361
        $y -= ($this->legend->iCircleRadius + 2) * $scaling + $this->legend->iBottomMargin * $scaling;
362
363
        // Adjust for bottom text
364
        if ($this->legend->iTxt != '') {
365
            // Setup font for text
366
            $value->Set($this->legend->iTxt);
367
            $y -= /*$this->legend->iTxtMargin + */$value->GetHeight($aImg);
368
        }
369
370
        // Stroke 0-circle
371
        $this->_ThickCircle(
372
            $aImg,
373
            $x,
374
            $y,
375
            $r,
376
            $this->legend->iCircleWeight,
377
            $this->legend->iCircleColor
378
        );
379
380
        // Remember the center of the circe
381
        $xc = $x;
382
        $yc = $y;
383
384
        $value->SetAlign('center', 'bottom');
385
        $x += $r + 1;
386
387
        // Stroke all used ranges
388
        $txty = $y -
389
        round($this->iLegweights[($this->scale->iMaxNum - 1) % $nlw] * $scaling) - 4 * $scaling;
390
        if ($this->scale->iMaxNum >= safe_count($this->iRanges)) {
391
            Util\JpGraphError::RaiseL(22007); //('To few values for the range legend.');
392
        }
393
        $i   = 0;
394
        $idx = 0;
395
        while ($i < $this->scale->iMaxNum) {
396
            $y1 = $y - round($this->iLegweights[$i % $nlw] * $scaling);
397
            $y2 = $y + round($this->iLegweights[$i % $nlw] * $scaling);
398
            $x2 = $x + $l;
399
            $aImg->SetColor($this->iLegColors[$i % $nlc]);
400
            $aImg->FilledRectangle($x, $y1, $x2, $y2);
401
            if ($this->iRangeStyle == RANGE_OVERLAPPING) {
402
                $lbl = sprintf($fmt, $this->iRanges[$idx], $this->iRanges[$idx + 1]);
403
            } else {
404
                $lbl = sprintf($fmt, $this->iRanges[$idx], $this->iRanges[$idx + 1]);
405
                ++$idx;
406
            }
407
            $value->Set($lbl);
408
            $value->Stroke($aImg, $x + $l / 2, $txty);
409
            $x = $x2;
410
            ++$i;
411
            ++$idx;
412
        }
413
414
        // Setup circle font
415
        $value->SetFont(
416
            $this->legend->iCircleFontFamily,
417
            $this->legend->iCircleFontStyle,
418
            $this->legend->iCircleFontSize * $scaling
419
        );
420
        $value->SetColor($this->legend->iCircleFontColor);
421
422
        // Stroke 0-circle text
423
        $value->Set($this->legend->iZCircleTxt);
424
        $value->SetAlign('center', 'center');
425
        $value->ParagraphAlign('center');
426
        $value->Stroke($aImg, $xc, $yc);
427
428
        // Setup circle font
429
        $value->SetFont(
430
            $this->legend->iTxtFontFamily,
431
            $this->legend->iTxtFontStyle,
432
            $this->legend->iTxtFontSize * $scaling
433
        );
434
        $value->SetColor($this->legend->iTxtFontColor);
435
436
        // Draw the text under the legend
437
        $value->Set($this->legend->iTxt);
438
        $value->SetAlign('center', 'top');
439
        $value->SetParagraphAlign('center');
440
        $value->Stroke($aImg, $xcenter, $y2 + $this->legend->iTxtMargin * $scaling);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $y2 does not seem to be defined for all execution paths leading up to this point.
Loading history...
441
    }
442
443
    public function SetAutoScaleAngle($aIsRegRose = true)
444
    {
445
        // If the user already has manually set an angle don't
446
        // trye to find a position
447
        if (is_numeric($this->scale->iAngle)) {
448
            return;
449
        }
450
451
        if ($aIsRegRose) {
452
            // Create a complete data for all directions
453
            // and translate string directions to ordinal values.
454
            // This will much simplify the logic below
455
            for ($i = 0; $i < 16; ++$i) {
456
                $dtxt = $this->iAllDirectionLabels[$i];
457
                if (!empty($this->iData[$dtxt])) {
458
                    $data[$i] = $this->iData[$dtxt];
459
                } elseif (!empty($this->iData[strtolower($dtxt)])) {
460
                    $data[$i] = $this->iData[strtolower($dtxt)];
461
                } elseif (!empty($this->iData[$i])) {
462
                    $data[$i] = $this->iData[$i];
463
                } else {
464
                    $data[$i] = [];
465
                }
466
            }
467
468
            // Find the leg which has the lowest weighted sum of number of data around it
469
            $c0    = array_sum($data[0]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.
Loading history...
470
            $c1    = array_sum($data[1]);
471
            $found = 1;
472
            $min   = $c0 + $c1 * 100; // Initialize to a high value
473
            for ($i = 1; $i < 15; ++$i) {
474
                $c2 = array_sum($data[$i + 1]);
475
476
                // Weight the leg we will use more to give preference
477
                // to a short middle leg even if the 3 way sum is similair
478
                $w = $c0 + 3 * $c1 + $c2;
479
                if ($w < $min) {
480
                    $min   = $w;
481
                    $found = $i;
482
                }
483
                $c0 = $c1;
484
                $c1 = $c2;
485
            }
486
            $this->scale->iAngle = $found * 22.5;
487
        } else {
488
            $n = safe_count($this->iData);
0 ignored issues
show
Unused Code introduced by
The assignment to $n is dead and can be removed.
Loading history...
489
            foreach ($this->iData as $dir => $leg) {
490
                if (!is_numeric($dir)) {
491
                    $pos = array_search(strtoupper($dir), $this->iAllDirectionLabels, true);
492
                    if ($pos !== false) {
493
                        $dir = $pos * 22.5;
494
                    }
495
                }
496
                $data[round($dir)] = $leg;
497
            }
498
499
            // Get all the angles for the data and sort it
500
            $keys = array_keys($data);
501
            sort($keys, SORT_NUMERIC);
502
503
            $n     = safe_count($data);
504
            $found = false;
505
            $max   = 0;
506
            for ($i = 0; $i < 15; ++$i) {
507
                $try_a = round(22.5 * $i);
508
509
                if ($try_a > $keys[$n - 1]) {
510
                    break;
511
                }
512
513
                if (in_array($try_a, $keys, true)) {
514
                    continue;
515
                }
516
517
                // Find the angle just lower than this
518
                $j = 0;
519
                while ($j < $n && $keys[$j] <= $try_a) {
520
                    ++$j;
521
                }
522
523
                if ($j == 0) {
524
                    $kj = 0;
525
                    $keys[$n - 1];
526
                    $d1 = 0;
527
                    abs($kj - $try_a);
528
                } else {
529
                    --$j;
530
                    $kj = $keys[$j];
531
                    $d1 = abs($kj - $try_a);
532
                }
533
534
                // Find the angle just larger than this
535
                $l = $n - 1;
536
                while ($l >= 0 && $keys[$l] >= $try_a) {
537
                    --$l;
538
                }
539
540
                if ($l == $n - 1) {
541
                    $kl = $keys[0];
542
                    $d2 = abs($kl - $try_a);
543
                } else {
544
                    ++$l;
545
                    $kl = $keys[$l];
546
                    $d2 = abs($kl - $try_a);
547
                }
548
549
                // Weight the distance so that legs with large spread
550
                // gets a better weight
551
                $w = $d1 + $d2;
552
                if ($i == 0) {
553
                    $w = round(1.4 * $w);
554
                }
555
                $diff = abs($d1 - $d2);
556
                $w *= (360 - $diff);
557
                if ($w > $max) {
558
                    $found = $i;
559
                    $max   = $w;
560
                }
561
            }
562
563
            $a = $found * 22.5;
564
565
            // Some heuristics to have some preferred positions
566
            if ($keys[$n - 1] < 25) {
567
                $a = 45;
568
            } elseif ($keys[0] > 60) {
569
                $a = 45;
570
            } elseif ($keys[0] > 25 && $keys[$n - 1] < 340) {
571
                $a = 0;
572
            } elseif ($keys[$n - 1] < 75) {
573
                $a = 90;
574
            } elseif ($keys[$n - 1] < 120) {
575
                $a = 135;
576
            } elseif ($keys[$n - 1] < 160) {
577
                $a = 180;
578
            }
579
580
            $this->scale->iAngle = $a;
581
        }
582
    }
583
584
    public function NormAngle($a)
585
    {
586
        while ($a > 360) {
587
            $a -= 360;
588
        }
589
590
        return $a;
591
    }
592
593
    public function SetLabelPosition($aPos)
594
    {
595
        $this->iLabelPositioning = $aPos;
596
    }
597
598
    public function _StrokeFreeRose($dblImg, $value, $scaling, $xc, $yc, $r, $ri)
599
    {
600
        // Plot radial grid lines and remember the end position
601
        // and the angle for later use when plotting the labels
602
        if ($this->iType != WINDROSE_TYPEFREE) {
603
            Util\JpGraphError::RaiseL(22008); //('Internal error: Trying to plot free Windrose even though type is not a free windorose');
604
        }
605
606
        // Check if we should auto-position the angle for the
607
        // labels. Basically we try to find a firection with smallest
608
        // (or none) data.
609
        $this->SetAutoScaleAngle(false);
610
611
        $nlc = safe_count($this->iLegColors);
612
        $nlw = safe_count($this->iLegweights);
613
614
        // Stroke grid lines for directions and remember the
615
        // position for the labels
616
        $txtpos = [];
617
        $num    = safe_count($this->iData);
618
619
        $keys = array_keys($this->iData);
620
621
        foreach ($this->iData as $dir => $legdata) {
622
            if (in_array($dir, $this->iAllDirectionLabels, true) === true) {
623
                $a = $this->iStandardDirections[strtoupper($dir)];
624
                if (in_array($a * 180 / M_PI, $keys, true)) {
625
                    Util\JpGraphError::RaiseL(22009, round($a * 180 / M_PI));
626
                    //('You have specified the same direction twice, once with an angle and once with a compass direction ('.$a*180/M_PI.' degrees.)');
627
                }
628
            } elseif (is_numeric($dir)) {
629
                $this->NormAngle($dir);
630
631
                if ($this->iOrdinalEncoding == KEYENCODING_CLOCKWISE) {
632
                    $dir = 360 - $dir;
633
                }
634
635
                $a = $dir * M_PI / 180;
636
            } else {
637
                Util\JpGraphError::RaiseL(22010); //('Direction must either be a numeric value or one of the 16 compass directions');
638
            }
639
640
            $xxc = round($xc + cos($a) * $ri);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $a does not seem to be defined for all execution paths leading up to this point.
Loading history...
641
            $yyc = round($yc - sin($a) * $ri);
642
            $x   = round($xc + cos($a) * $r);
643
            $y   = round($yc - sin($a) * $r);
644
            if (empty($this->iRadialColorArray[$dir])) {
645
                $dblImg->SetColor($this->iGridColor2);
646
            } else {
647
                $dblImg->SetColor($this->iRadialColorArray[$dir]);
648
            }
649
            if (empty($this->iRadialWeightArray[$dir])) {
650
                $dblImg->SetLineWeight($this->iRadialGridWeight);
651
            } else {
652
                $dblImg->SetLineWeight($this->iRadialWeightArray[$dir]);
653
            }
654
            if (empty($this->iRadialStyleArray[$dir])) {
655
                $dblImg->SetLineStyle($this->iRadialGridStyle);
656
            } else {
657
                $dblImg->SetLineStyle($this->iRadialStyleArray[$dir]);
658
            }
659
            $dblImg->StyleLine($xxc, $yyc, $x, $y);
660
            $txtpos[] = [$x, $y, $a];
661
        }
662
        $dblImg->SetLineWeight(1);
663
664
        // Setup labels
665
        $lr = $scaling * $this->iLabelMargin;
666
667
        if ($this->iLabelPositioning == LBLPOSITION_EDGE) {
668
            $value->SetAlign('left', 'top');
669
        } else {
670
            $value->SetAlign('center', 'center');
671
            $value->SetMargin(0);
672
        }
673
674
        for ($i = 0; $i < $num; ++$i) {
675
            list($x, $y, $a) = $txtpos[$i];
676
677
            // Determine the label
678
679
            $da = $a * 180 / M_PI;
680
            if ($this->iOrdinalEncoding == KEYENCODING_CLOCKWISE) {
681
                $da = 360 - $da;
682
            }
683
684
            //$da = 360-$da;
685
686
            if (!empty($this->iLabels[$keys[$i]])) {
687
                $lbl = $this->iLabels[$keys[$i]];
688
            } else {
689
                $lbl = sprintf($this->iLabelFormatString, $da);
690
            }
691
692
            if ($this->iLabelPositioning == LBLPOSITION_CENTER) {
693
                $dx = $dy = 0;
694
            } else {
695
                // LBLPOSIITON_EDGE
696
                if ($a >= 7 * M_PI / 4 || $a <= M_PI / 4) {
697
                    $dx = 0;
698
                }
699
700
                if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
701
                    $dx = ($a - M_PI / 4) * 2 / M_PI;
702
                }
703
704
                if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
705
                    $dx = 1;
706
                }
707
708
                if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
709
                    $dx = (1 - ($a - M_PI * 5 / 4) * 2 / M_PI);
710
                }
711
712
                if ($a >= 7 * M_PI / 4) {
713
                    $dy = (($a - M_PI) - 3 * M_PI / 4) * 2 / M_PI;
714
                }
715
716
                if ($a <= M_PI / 4) {
717
                    $dy = (0.5 + $a * 2 / M_PI);
718
                }
719
720
                if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
721
                    $dy = 1;
722
                }
723
724
                if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
725
                    $dy = (1 - ($a - 3 * M_PI / 4) * 2 / M_PI);
726
                }
727
728
                if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
729
                    $dy = 0;
730
                }
731
            }
732
733
            $value->Set($lbl);
734
            $th = $value->GetHeight($dblImg);
735
            $tw = $value->GetWidth($dblImg);
736
            $xt = round($lr * cos($a) + $x) - $dx * $tw;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dx does not seem to be defined for all execution paths leading up to this point.
Loading history...
737
            $yt = round($y - $lr * sin($a)) - $dy * $th;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dy does not seem to be defined for all execution paths leading up to this point.
Loading history...
738
739
            $value->Stroke($dblImg, $xt, $yt);
740
        }
741
742
        if (__DEBUG) {
743
            $dblImg->SetColor('red');
744
            $dblImg->Circle($xc, $yc, $lr + $r);
745
        }
746
747
        // Stroke all the legs
748
        reset($this->iData);
749
        $i = 0;
750
        foreach ($this->iData as $dir => $legdata) {
751
            $legdata = array_slice($legdata, 1);
752
            $nn      = safe_count($legdata);
753
754
            $a   = $txtpos[$i][2];
755
            $rri = $ri / $scaling;
756
            for ($j = 0; $j < $nn; ++$j) {
757
                // We want the non scaled original radius
758
                $legr = $this->scale->RelTranslate($legdata[$j], $r / $scaling, $ri / $scaling);
759
                $this->_StrokeWindLeg(
760
                    $dblImg,
761
                    $xc,
762
                    $yc,
763
                    $a,
764
                    $rri * $scaling,
765
                    $legr * $scaling,
766
                    $this->iLegweights[$j % $nlw] * $scaling,
767
                    $this->iLegColors[$j % $nlc]
768
                );
769
                $rri += $legr;
770
            }
771
            ++$i;
772
        }
773
    }
774
775
    // Translate potential string specified compass labels to their
776
    // corresponding index.
777
    public function FixupIndexes($aDataArray, $num)
778
    {
779
        $ret  = [];
780
        $keys = array_keys($aDataArray);
781
        foreach ($aDataArray as $idx => $data) {
782
            if (is_string($idx)) {
783
                $idx = strtoupper($idx);
784
                $res = array_search($idx, $this->iAllDirectionLabels, true);
785
                if ($res === false) {
786
                    Util\JpGraphError::RaiseL(22011, $idx); //('Windrose index must be numeric or direction label. You have specified index='.$idx);
787
                }
788
                $idx = $res;
789
                if ($idx % (16 / $num) !== 0) {
790
                    Util\JpGraphError::RaiseL(22012); //('Windrose radial axis specification contains a direction which is not enabled.');
791
                }
792
                $idx /= (16 / $num);
793
794
                if (in_array($idx, $keys, 1)) {
795
                    Util\JpGraphError::RaiseL(22013, $idx); //('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index='.$idx.')');
796
                }
797
            }
798
            if ($idx < 0 || $idx > 15) {
799
                Util\JpGraphError::RaiseL(22014); //('Index for copmass direction must be between 0 and 15.');
800
            }
801
            $ret[$idx] = $data;
802
        }
803
804
        return $ret;
805
    }
806
807
    public function _StrokeRegularRose($dblImg, $value, $scaling, $xc, $yc, $r, $ri)
808
    {
809
        // _StrokeRegularRose($dblImg,$xc,$yc,$r,$ri)
810
        // Plot radial grid lines and remember the end position
811
        // and the angle for later use when plotting the labels
812
        switch ($this->iType) {
813
            case WINDROSE_TYPE4:
814
                $num = 4;
815
816
                break;
817
            case WINDROSE_TYPE8:
818
                $num = 8;
819
820
                break;
821
            case WINDROSE_TYPE16:
822
                $num = 16;
823
824
                break;
825
            default:
826
                Util\JpGraphError::RaiseL(22015); //('You have specified an undefined Windrose plot type.');
827
        }
828
829
        // Check if we should auto-position the angle for the
830
        // labels. Basically we try to find a firection with smallest
831
        // (or none) data.
832
        $this->SetAutoScaleAngle(true);
833
834
        $nlc = safe_count($this->iLegColors);
835
        $nlw = safe_count($this->iLegweights);
836
837
        $this->iRadialColorArray  = $this->FixupIndexes($this->iRadialColorArray, $num);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $num does not seem to be defined for all execution paths leading up to this point.
Loading history...
838
        $this->iRadialWeightArray = $this->FixupIndexes($this->iRadialWeightArray, $num);
839
        $this->iRadialStyleArray  = $this->FixupIndexes($this->iRadialStyleArray, $num);
840
841
        $txtpos = [];
842
        $a      = 2 * M_PI / $num;
843
        $dblImg->SetColor($this->iGridColor2);
844
        $dblImg->SetLineStyle($this->iRadialGridStyle);
845
        $dblImg->SetLineWeight($this->iRadialGridWeight);
846
847
        // Translate any name specified directions to the index
848
        // so we can easily use it in the loop below
849
        for ($i = 0; $i < $num; ++$i) {
850
            $xxc = round($xc + cos($a * $i) * $ri);
851
            $yyc = round($yc - sin($a * $i) * $ri);
852
            $x   = round($xc + cos($a * $i) * $r);
853
            $y   = round($yc - sin($a * $i) * $r);
854
            if (empty($this->iRadialColorArray[$i])) {
855
                $dblImg->SetColor($this->iGridColor2);
856
            } else {
857
                $dblImg->SetColor($this->iRadialColorArray[$i]);
858
            }
859
            if (empty($this->iRadialWeightArray[$i])) {
860
                $dblImg->SetLineWeight($this->iRadialGridWeight);
861
            } else {
862
                $dblImg->SetLineWeight($this->iRadialWeightArray[$i]);
863
            }
864
            if (empty($this->iRadialStyleArray[$i])) {
865
                $dblImg->SetLineStyle($this->iRadialGridStyle);
866
            } else {
867
                $dblImg->SetLineStyle($this->iRadialStyleArray[$i]);
868
            }
869
870
            $dblImg->StyleLine($xxc, $yyc, $x, $y);
871
            $txtpos[] = [$x, $y, $a * $i];
872
        }
873
        $dblImg->SetLineWeight(1);
874
875
        $lr = $scaling * $this->iLabelMargin;
876
        if ($this->iLabelPositioning == LBLPOSITION_CENTER) {
877
            $value->SetAlign('center', 'center');
878
        } else {
879
            $value->SetAlign('left', 'top');
880
            $value->SetMargin(0);
881
            $lr /= 2;
882
        }
883
884
        for ($i = 0; $i < $num; ++$i) {
885
            list($x, $y, $a) = $txtpos[$i];
886
887
            // Set the position of the label
888
            if ($this->iLabelPositioning == LBLPOSITION_CENTER) {
889
                $dx = $dy = 0;
890
            } else {
891
                // LBLPOSIITON_EDGE
892
                if ($a >= 7 * M_PI / 4 || $a <= M_PI / 4) {
893
                    $dx = 0;
894
                }
895
896
                if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
897
                    $dx = ($a - M_PI / 4) * 2 / M_PI;
898
                }
899
900
                if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
901
                    $dx = 1;
902
                }
903
904
                if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
905
                    $dx = (1 - ($a - M_PI * 5 / 4) * 2 / M_PI);
906
                }
907
908
                if ($a >= 7 * M_PI / 4) {
909
                    $dy = (($a - M_PI) - 3 * M_PI / 4) * 2 / M_PI;
910
                }
911
912
                if ($a <= M_PI / 4) {
913
                    $dy = (0.5 + $a * 2 / M_PI);
914
                }
915
916
                if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
917
                    $dy = 1;
918
                }
919
920
                if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
921
                    $dy = (1 - ($a - 3 * M_PI / 4) * 2 / M_PI);
922
                }
923
924
                if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
925
                    $dy = 0;
926
                }
927
            }
928
929
            $value->Set($this->iAllDirectionLabels[$i * (16 / $num)]);
930
            $th = $value->GetHeight($dblImg);
931
            $tw = $value->GetWidth($dblImg);
932
            $xt = round($lr * cos($a) + $x) - $dx * $tw;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dx does not seem to be defined for all execution paths leading up to this point.
Loading history...
933
            $yt = round($y - $lr * sin($a)) - $dy * $th;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dy does not seem to be defined for all execution paths leading up to this point.
Loading history...
934
935
            $value->Stroke($dblImg, $xt, $yt);
936
        }
937
938
        if (__DEBUG) {
939
            $dblImg->SetColor('red');
940
            $dblImg->Circle($xc, $yc, $lr + $r);
941
        }
942
943
        // Stroke all the legs
944
        reset($this->iData);
945
        $keys = array_keys($this->iData);
946
        foreach ($this->iData as $idx => $legdata) {
947
            $legdata = array_slice($legdata, 1);
948
            $nn      = safe_count($legdata);
949
            if (is_string($idx)) {
950
                $idx = strtoupper($idx);
951
                $idx = array_search($idx, $this->iAllDirectionLabels, true);
952
                if ($idx === false) {
953
                    Util\JpGraphError::RaiseL(22016); //('Windrose leg index must be numeric or direction label.');
954
                }
955
                if ($idx % (16 / $num) !== 0) {
956
                    Util\JpGraphError::RaiseL(22017); //('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.');
957
                }
958
                $idx /= (16 / $num);
959
960
                if (in_array($idx, $keys, 1)) {
961
                    Util\JpGraphError::RaiseL(22018, $idx); //('You have specified data for the same compass direction twice, once with text and once with index (Index='.$idx.')');
962
                }
963
            }
964
            if ($idx < 0 || $idx > 15) {
965
                Util\JpGraphError::RaiseL(22019); //('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.');
966
            }
967
            $a = $idx * (360 / $num);
968
            $a *= M_PI / 180.0;
969
            $rri = $ri / $scaling;
970
            for ($j = 0; $j < $nn; ++$j) {
971
                // We want the non scaled original radius
972
                $legr = $this->scale->RelTranslate($legdata[$j], $r / $scaling, $ri / $scaling);
973
                $this->_StrokeWindLeg(
974
                    $dblImg,
975
                    $xc,
976
                    $yc,
977
                    $a,
978
                    $rri * $scaling,
979
                    $legr * $scaling,
980
                    $this->iLegweights[$j % $nlw] * $scaling,
981
                    $this->iLegColors[$j % $nlc]
982
                );
983
                $rri += $legr;
984
            }
985
        }
986
    }
987
988
    public function getWidth($aImg)
989
    {
990
        $scaling = 1; //$this->iAntiAlias ? 2 : 1 ;
991
        if ($this->iSize > 0 && $this->iSize < 1) {
992
            $this->iSize *= min($aImg->width, $aImg->height);
993
        }
994
995
        $value = new Text\Text();
996
        $value->SetFont($this->iFontFamily, $this->iFontStyle, $this->iFontSize * $scaling);
997
        $value->SetColor($this->iFontColor);
998
        // Setup extra size around the graph needed so that the labels
999
        // doesn't get cut. For this we need to find the largest label.
1000
        // The code below gives a possible a little to large margin. The
1001
        // really, really proper way would be to account for what angle
1002
        // the label are at
1003
        $n = safe_count($this->iLabels);
1004
        if ($n > 0) {
1005
            $maxh = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $maxh is dead and can be removed.
Loading history...
1006
            $maxw = 0;
1007
            foreach ($this->iLabels as $key => $lbl) {
1008
                $value->Set($lbl);
1009
                $maxw = max($maxw, $value->GetWidth($aImg));
1010
            }
1011
        } else {
1012
            $value->Set('888.888'); // Dummy value to get width/height
1013
            $maxw = $value->GetWidth($aImg);
1014
        }
1015
        // Add an extra margin of 50% the font size
1016
        $maxw += round($this->iFontSize * $scaling * 0.4);
1017
1018
        $valxmarg = 1.5 * $maxw + 2 * $this->iLabelMargin * $scaling;
1019
        $w        = round($this->iSize * $scaling + $valxmarg);
1020
1021
        // Make sure that the width of the legend fits
1022
        $legendwidth = $this->_StrokeLegend($aImg, 0, 0, $scaling, true) + 10 * $scaling;
1023
        $w           = max($w, $legendwidth);
1024
1025
        return $w;
1026
    }
1027
1028
    public function getHeight($aImg)
1029
    {
1030
        $scaling = 1; //$this->iAntiAlias ? 2 : 1 ;
1031
        if ($this->iSize > 0 && $this->iSize < 1) {
1032
            $this->iSize *= min($aImg->width, $aImg->height);
1033
        }
1034
1035
        $value = new Text\Text();
1036
        $value->SetFont($this->iFontFamily, $this->iFontStyle, $this->iFontSize * $scaling);
1037
        $value->SetColor($this->iFontColor);
1038
        // Setup extra size around the graph needed so that the labels
1039
        // doesn't get cut. For this we need to find the largest label.
1040
        // The code below gives a possible a little to large margin. The
1041
        // really, really proper way would be to account for what angle
1042
        // the label are at
1043
        $n = safe_count($this->iLabels);
1044
        if ($n > 0) {
1045
            $maxh = 0;
1046
            $maxw = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $maxw is dead and can be removed.
Loading history...
1047
            foreach ($this->iLabels as $key => $lbl) {
1048
                $value->Set($lbl);
1049
                $maxh = max($maxh, $value->GetHeight($aImg));
1050
            }
1051
        } else {
1052
            $value->Set('180.8'); // Dummy value to get width/height
1053
            $maxh = $value->GetHeight($aImg);
1054
        }
1055
        // Add an extra margin of 50% the font size
1056
        //$maxh += round($this->iFontSize*$scaling * 0.5) ;
1057
        $valymarg = 2 * $maxh + 2 * $this->iLabelMargin * $scaling;
1058
1059
        $legendheight = round($this->legend->iShow ? 1 : 0);
1060
        $legendheight *= max($this->legend->iCircleRadius * 2, $this->legend->iTxtFontSize * 2) +
1061
        $this->legend->iMargin + $this->legend->iBottomMargin + 2;
1062
        $legendheight *= $scaling;
1063
        $h = round($this->iSize * $scaling + $valymarg) + $legendheight;
1064
1065
        return $h;
1066
    }
1067
1068
    public function Stroke($aGraph)
1069
    {
1070
        $aImg = $aGraph->img;
1071
1072
        if ($this->iX > 0 && $this->iX < 1) {
1073
            $this->iX = round($aImg->width * $this->iX);
1074
        }
1075
1076
        if ($this->iY > 0 && $this->iY < 1) {
1077
            $this->iY = round($aImg->height * $this->iY);
1078
        }
1079
1080
        if ($this->iSize > 0 && $this->iSize < 1) {
1081
            $this->iSize *= min($aImg->width, $aImg->height);
1082
        }
1083
1084
        if ($this->iCenterSize > 0 && $this->iCenterSize < 1) {
1085
            $this->iCenterSize *= $this->iSize;
1086
        }
1087
1088
        $this->scale->AutoScale(($this->iSize - $this->iCenterSize) / 2, round(2.5 * $this->scale->iFontSize));
1089
1090
        $scaling = $this->iAntiAlias ? 2 : 1;
1091
1092
        $value = new Text\Text();
1093
        $value->SetFont($this->iFontFamily, $this->iFontStyle, $this->iFontSize * $scaling);
1094
        $value->SetColor($this->iFontColor);
1095
1096
        $legendheight = round($this->legend->iShow ? 1 : 0);
1097
        $legendheight *= max($this->legend->iCircleRadius * 2, $this->legend->iTxtFontSize * 2) +
1098
        $this->legend->iMargin + $this->legend->iBottomMargin + 2;
1099
        $legendheight *= $scaling;
1100
1101
        $w = $scaling * $this->getWidth($aImg);
1102
        $h = $scaling * $this->getHeight($aImg);
1103
1104
        // Copy back the double buffered image to the proper canvas
1105
        $ww = $w / $scaling;
1106
        $hh = $h / $scaling;
1107
1108
        // Create the double buffer
1109
        if ($this->iAntiAlias) {
1110
            $dblImg = new Image\RotImage($w, $h);
1111
            // Set the background color
1112
            $dblImg->SetColor($this->iColor);
1113
            $dblImg->FilledRectangle(0, 0, $w, $h);
1114
        } else {
1115
            $dblImg = $aImg;
1116
            // Make sure the ix and it coordinates correpond to the new top left center
1117
            $dblImg->SetTranslation($this->iX - $w / 2, $this->iY - $h / 2);
1118
        }
1119
1120
        if (__DEBUG) {
1121
            $dblImg->SetColor('red');
1122
            $dblImg->Rectangle(0, 0, $w - 1, $h - 1);
1123
        }
1124
1125
        $dblImg->SetColor('black');
1126
1127
        if ($this->iShowBox) {
1128
            $dblImg->SetColor($this->iBoxColor);
1129
            $old = $dblImg->SetLineWeight($this->iBoxWeight);
1130
            $dblImg->SetLineStyle($this->iBoxStyle);
1131
            $dblImg->Rectangle(0, 0, $w - 1, $h - 1);
1132
            $dblImg->SetLineWeight($old);
1133
        }
1134
1135
        $xc = round($w / 2);
1136
        $yc = round(($h - $legendheight) / 2);
1137
1138
        if (__DEBUG) {
1139
            $dblImg->SetColor('red');
1140
            $old = $dblImg->SetLineWeight(2);
1141
            $dblImg->Line($xc - 5, $yc - 5, $xc + 5, $yc + 5);
1142
            $dblImg->Line($xc + 5, $yc - 5, $xc - 5, $yc + 5);
1143
            $dblImg->SetLineWeight($old);
1144
        }
1145
1146
        $this->iSize *= $scaling;
1147
1148
        // Inner circle size
1149
        $ri = $this->iCenterSize / 2;
1150
1151
        // Full circle radius
1152
        $r = round($this->iSize / 2);
1153
1154
        // Get number of grid circles
1155
        $n = $this->scale->GetNumCirc();
1156
1157
        // Plot circle grids
1158
        $ri *= $scaling;
1159
        $rr = round(($r - $ri) / $n);
1160
        for ($i = 1; $i <= $n; ++$i) {
1161
            $this->_ThickCircle(
1162
                $dblImg,
1163
                $xc,
1164
                $yc,
1165
                $rr * $i + $ri,
1166
                $this->iCircGridWeight,
1167
                $this->iGridColor1
1168
            );
1169
        }
1170
1171
        $num = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $num is dead and can be removed.
Loading history...
1172
1173
        if ($this->iType == WINDROSE_TYPEFREE) {
1174
            $this->_StrokeFreeRose($dblImg, $value, $scaling, $xc, $yc, $r, $ri);
1175
        } else {
1176
            // Check if we need to re-code the interpretation of the ordinal
1177
            // number in the data. Internally ordinal value 0 is East and then
1178
            // counted anti-clockwise. The user might choose an encoding
1179
            // that have 0 being the first axis to the right of the "N" axis and then
1180
            // counted clock-wise
1181
            if ($this->iOrdinalEncoding == KEYENCODING_CLOCKWISE) {
1182
                if ($this->iType == WINDROSE_TYPE16) {
1183
                    $const1 = 19;
1184
                    $const2 = 16;
1185
                } elseif ($this->iType == WINDROSE_TYPE8) {
1186
                    $const1 = 9;
1187
                    $const2 = 8;
1188
                } else {
1189
                    $const1 = 4;
1190
                    $const2 = 4;
1191
                }
1192
                $tmp = [];
1193
                $n   = safe_count($this->iData);
0 ignored issues
show
Unused Code introduced by
The assignment to $n is dead and can be removed.
Loading history...
1194
                foreach ($this->iData as $key => $val) {
1195
                    if (is_numeric($key)) {
1196
                        $key = ($const1 - $key) % $const2;
1197
                    }
1198
                    $tmp[$key] = $val;
1199
                }
1200
                $this->iData = $tmp;
1201
            }
1202
            $this->_StrokeRegularRose($dblImg, $value, $scaling, $xc, $yc, $r, $ri);
1203
        }
1204
1205
        // Stroke the labels
1206
        $this->scale->iFontSize *= $scaling;
1207
        $this->scale->iZFontSize *= $scaling;
1208
        $this->scale->StrokeLabels($dblImg, $xc, $yc, $ri, $rr);
1209
1210
        // Stroke the inner circle again since the legs
1211
        // might have written over it
1212
        $this->_ThickCircle($dblImg, $xc, $yc, $ri, $this->iCircGridWeight, $this->iGridColor1);
1213
1214
        if ($ww > $aImg->width) {
1215
            Util\JpGraphError::RaiseL(22020);
1216
            //('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.');
1217
        }
1218
1219
        $x = $xc;
1220
        $y = $h;
1221
        $this->_StrokeLegend($dblImg, $x, $y, $scaling);
1222
1223
        if ($this->iAntiAlias) {
1224
            $aImg->Copy($dblImg->img, $this->iX - $ww / 2, $this->iY - $hh / 2, 0, 0, $ww, $hh, $w, $h);
1225
        }
1226
1227
        // We need to restore the translation matrix
1228
        $aImg->SetTranslation(0, 0);
1229
    }
1230
}
1231