Passed
Push — master ( 8f5e6a...061d3e )
by Felipe
03:26
created

PiePlot::SetGuideLines()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Amenadiel\JpGraph\Plot;
3
4
use Amenadiel\JpGraph\Graph;
5
use Amenadiel\JpGraph\Text;
6
use Amenadiel\JpGraph\Util;
7
8
/*=======================================================================
9
// File:        JPGRAPH_PIE.PHP
10
// Description: Pie plot extension for JpGraph
11
// Created:     2001-02-14
12
// Ver:         $Id: jpgraph_pie.php 1926 2010-01-11 16:33:07Z ljp $
13
//
14
// Copyright (c) Asial Corporation. All rights reserved.
15
//========================================================================
16
 */
17
18
// Defines for PiePlot::SetLabelType()
1 ignored issue
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
19
define("PIE_VALUE_ABS", 1);
20
define("PIE_VALUE_PER", 0);
21
define("PIE_VALUE_PERCENTAGE", 0);
22
define("PIE_VALUE_ADJPERCENTAGE", 2);
23
define("PIE_VALUE_ADJPER", 2);
24
25
//===================================================
26
// CLASS PiePlot
27
// Description: Draws a pie plot
28
//===================================================
29
class PiePlot
30
{
31
    public $posx                     = 0.5;
32
    public $posy                     = 0.5;
33
    public $is_using_plot_theme      = false;
34
    public $theme                    = "earth";
35
    protected $use_plot_theme_colors = false;
36
    protected $radius                = 0.3;
37
    protected $explode_radius        = array();
38
    protected $explode_all        = false;
39
    protected $explode_r        = 20;
40
    protected $labels                = null;
41
    protected $legends                = null;
42
    protected $csimtargets           = null;
43
    protected $csimwintargets           = null; // Array of targets for CSIM
44
    protected $csimareas             = ''; // Generated CSIM text
45
    protected $csimalts              = null; // ALT tags for corresponding target
46
    protected $data                  = null;
47
    public $title;
48
    protected $startangle    = 0;
49
    protected $weight        = 1;
50
    protected $color        = "black";
51
    protected $legend_margin = 6;
52
    protected $show_labels = true;
53
    protected $themearr      = array(
54
        "earth"  => array(136, 34, 40, 45, 46, 62, 63, 134, 74, 10, 120, 136, 141, 168, 180, 77, 209, 218, 346, 395, 89, 430),
55
        "pastel" => array(27, 415, 128, 59, 66, 79, 105, 110, 42, 147, 152, 230, 236, 240, 331, 337, 405, 38),
56
        "water"  => array(8, 370, 24, 40, 335, 56, 213, 237, 268, 14, 326, 387, 10, 388),
57
        "sand"   => array(27, 168, 34, 170, 19, 50, 65, 72, 131, 209, 46, 393));
58
    protected $setslicecolors = array();
59
    protected $labeltype      = 0; // Default to percentage
60
    protected $pie_border     = true;
61
    protected $pie_interior_border     = true;
62
    public $value;
63
    protected $ishadowcolor      = '';
64
    protected $ishadowdrop      = 4;
65
    protected $ilabelposadj      = 1;
66
    protected $legendcsimtargets = array();
67
    protected $legendcsimwintargets = array();
68
    protected $legendcsimalts    = array();
69
    protected $adjusted_data     = array();
70
    public $guideline            = null;
71
    protected $guidelinemargin   = 10;
72
    protected $iShowGuideLineForSingle   = false;
73
    protected $iGuideLineCurve   = false;
74
    protected $iGuideVFactor   = 1.4;
75
    protected $iGuideLineRFactor   = 0.8;
76
    protected $la                = array(); // Holds the exact angle for each label
77
78
    //---------------
79
    // CONSTRUCTOR
80 View Code Duplication
    public function __construct($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
81
    {
82
        $this->data  = array_reverse($data);
83
        $this->title = new Text\Text("");
84
        $this->title->SetFont(FF_DEFAULT, FS_BOLD);
85
        $this->value = new DisplayValue();
86
        $this->value->Show();
87
        $this->value->SetFormat('%.1f%%');
88
        $this->guideline = new Graph\LineProperty();
89
    }
90
91
    //---------------
92
    // PUBLIC METHODS
93
    public function SetCenter($x, $y = 0.5)
94
    {
95
        $this->posx = $x;
96
        $this->posy = $y;
97
    }
98
99
    // Enable guideline and set drwaing policy
100
    public function SetGuideLines($aFlg = true, $aCurved = true, $aAlways = false)
101
    {
102
        $this->guideline->Show($aFlg);
103
        $this->iShowGuideLineForSingle = $aAlways;
104
        $this->iGuideLineCurve         = $aCurved;
105
    }
106
107
    // Adjuste the distance between labels and labels and pie
108
    public function SetGuideLinesAdjust($aVFactor, $aRFactor = 0.8)
109
    {
110
        $this->iGuideVFactor     = $aVFactor;
111
        $this->iGuideLineRFactor = $aRFactor;
112
    }
113
114
    public function SetColor($aColor)
115
    {
116
        $this->color = $aColor;
117
    }
118
119
    public function SetSliceColors($aColors)
120
    {
121
        $this->setslicecolors = $aColors;
122
    }
123
124
    public function SetShadow($aColor = 'darkgray', $aDropWidth = 4)
125
    {
126
        $this->ishadowcolor = $aColor;
127
        $this->ishadowdrop  = $aDropWidth;
128
    }
129
130
    public function SetCSIMTargets($aTargets, $aAlts = '', $aWinTargets = '')
131
    {
132
        $this->csimtargets = array_reverse($aTargets);
133
        if (is_array($aWinTargets)) {
134
            $this->csimwintargets = array_reverse($aWinTargets);
135
        }
136
137
        if (is_array($aAlts)) {
138
            $this->csimalts = array_reverse($aAlts);
139
        }
140
    }
141
142
    public function GetCSIMareas()
143
    {
144
        return $this->csimareas;
145
    }
146
147
    public function AddSliceToCSIM($i, $xc, $yc, $radius, $sa, $ea)
148
    {
149
        //Slice number, ellipse centre (x,y), height, width, start angle, end angle
150
        while ($sa > 2 * M_PI) {
151
            $sa = $sa - 2 * M_PI;
152
        }
153
154
        while ($ea > 2 * M_PI) {
155
            $ea = $ea - 2 * M_PI;
156
        }
157
158
        $sa = 2 * M_PI - $sa;
159
        $ea = 2 * M_PI - $ea;
160
161
        // Special case when we have only one slice since then both start and end
162
        // angle will be == 0
163 View Code Duplication
        if (abs($sa - $ea) < 0.0001) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
            $sa = 2 * M_PI;
165
            $ea = 0;
166
        }
167
168
        //add coordinates of the centre to the map
169
        $xc     = floor($xc);
170
        $yc     = floor($yc);
171
        $coords = "$xc, $yc";
172
173
        //add coordinates of the first point on the arc to the map
174
        $xp = floor(($radius * cos($ea)) + $xc);
175
        $yp = floor($yc - $radius * sin($ea));
176
        $coords .= ", $xp, $yp";
177
178
        //add coordinates every 0.2 radians
179
        $a = $ea + 0.2;
180
181
        // If we cross the 360-limit with a slice we need to handle
182
        // the fact that end angle is smaller than start
183 View Code Duplication
        if ($sa < $ea) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
            while ($a <= 2 * M_PI) {
185
                $xp = floor($radius * cos($a) + $xc);
186
                $yp = floor($yc - $radius * sin($a));
187
                $coords .= ", $xp, $yp";
188
                $a += 0.2;
189
            }
190
            $a -= 2 * M_PI;
191
        }
192
193
        while ($a < $sa) {
194
            $xp = floor($radius * cos($a) + $xc);
195
            $yp = floor($yc - $radius * sin($a));
196
            $coords .= ", $xp, $yp";
197
            $a += 0.2;
198
        }
199
200
        //Add the last point on the arc
201
        $xp = floor($radius * cos($sa) + $xc);
202
        $yp = floor($yc - $radius * sin($sa));
203
        $coords .= ", $xp, $yp";
204 View Code Duplication
        if (!empty($this->csimtargets[$i])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
            $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"" . $this->csimtargets[$i] . "\"";
206
            $tmp = "";
0 ignored issues
show
Unused Code introduced by
$tmp is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
207
            if (!empty($this->csimwintargets[$i])) {
208
                $this->csimareas .= " target=\"" . $this->csimwintargets[$i] . "\" ";
209
            }
210
            if (!empty($this->csimalts[$i])) {
211
                $tmp = sprintf($this->csimalts[$i], $this->data[$i]);
212
                $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
213
            }
214
            $this->csimareas .= " />\n";
215
        }
216
    }
217
218
    public function SetTheme($aTheme)
219
    {
220
        //        Util\JpGraphError::RaiseL(15012,$aTheme);
1 ignored issue
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
221
        //        return;
222
223
        if (in_array($aTheme, array_keys($this->themearr))) {
224
            $this->theme               = $aTheme;
225
            $this->is_using_plot_theme = true;
226
        } else {
227
            Util\JpGraphError::RaiseL(15001, $aTheme); //("PiePLot::SetTheme() Unknown theme: $aTheme");
228
        }
229
    }
230
231
    public function ExplodeSlice($e, $radius = 20)
232
    {
233
        if (!is_integer($e)) {
234
            Util\JpGraphError::RaiseL(15002);
235
        }
236
        //('Argument to PiePlot::ExplodeSlice() must be an integer');
237
        $this->explode_radius[$e] = $radius;
238
    }
239
240
    public function ExplodeAll($radius = 20)
241
    {
242
        $this->explode_all = true;
243
        $this->explode_r   = $radius;
244
    }
245
246
    public function Explode($aExplodeArr)
247
    {
248
        if (!is_array($aExplodeArr)) {
249
            Util\JpGraphError::RaiseL(15003);
250
            //("Argument to PiePlot::Explode() must be an array with integer distances.");
251
        }
252
        $this->explode_radius = $aExplodeArr;
253
    }
254
255
    public function SetStartAngle($aStart)
256
    {
257
        if ($aStart < 0 || $aStart > 360) {
258
            Util\JpGraphError::RaiseL(15004); //('Slice start angle must be between 0 and 360 degrees.');
259
        }
260
        if ($aStart == 0) {
261
            $this->startangle = 0;
262
        } else {
263
            $this->startangle = 360 - $aStart;
0 ignored issues
show
Documentation Bug introduced by
It seems like 360 - $aStart can also be of type double. However, the property $startangle is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
264
            $this->startangle *= M_PI / 180;
265
        }
266
    }
267
268
    // Size in percentage
269
    public function SetSize($aSize)
270
    {
271
        if (($aSize > 0 && $aSize <= 0.5) || ($aSize > 10 && $aSize < 1000)) {
272
            $this->radius = $aSize;
273
        } else {
274
            Util\JpGraphError::RaiseL(15006);
275
        }
276
277
        //("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels  in the range [10, 1000]");
278
    }
279
280
    // Set label arrays
281
    public function SetLegends($aLegend)
282
    {
283
        $this->legends = $aLegend;
284
    }
285
286
    // Set text labels for slices
287
    public function SetLabels($aLabels, $aLblPosAdj = "auto")
288
    {
289
        $this->labels       = array_reverse($aLabels);
290
        $this->ilabelposadj = $aLblPosAdj;
0 ignored issues
show
Documentation Bug introduced by
The property $ilabelposadj was declared of type integer, but $aLblPosAdj is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
291
    }
292
293
    public function SetLabelPos($aLblPosAdj)
294
    {
295
        $this->ilabelposadj = $aLblPosAdj;
296
    }
297
298
    // Should we display actual value or percentage?
299
    public function SetLabelType($aType)
300
    {
301
        if ($aType < 0 || $aType > 2) {
302
            Util\JpGraphError::RaiseL(15008, $aType);
303
        }
304
305
        //("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).");
306
        $this->labeltype = $aType;
307
    }
308
309
    // Deprecated.
310
    public function SetValueType($aType)
311
    {
312
        $this->SetLabelType($aType);
313
    }
314
315
    // Should the circle around a pie plot be displayed
316
    public function ShowBorder($exterior = true, $interior = true)
317
    {
318
        $this->pie_border          = $exterior;
319
        $this->pie_interior_border = $interior;
320
    }
321
322
    // Setup the legends
323
    public function Legend($graph)
324
    {
325
        $colors = array_keys($graph->img->rgb->rgb_table);
326
        sort($colors);
327
        $ta = $this->themearr[$this->theme];
328
        $n  = count($this->data);
329
330
        if ($this->setslicecolors == null) {
331
            $numcolors = count($ta);
332
            if (class_exists('PiePlot3D', false) && ($this instanceof PiePlot3D)) {
333
                $ta = array_reverse(array_slice($ta, 0, $n));
334
            }
335
        } else {
336
            $this->setslicecolors = array_slice($this->setslicecolors, 0, $n);
337
            $numcolors            = count($this->setslicecolors);
338
            if ($graph->pieaa && !($this instanceof PiePlot3D)) {
339
                $this->setslicecolors = array_reverse($this->setslicecolors);
340
            }
341
        }
342
343
        $sum = 0;
344
        for ($i = 0; $i < $n; ++$i) {
345
            $sum += $this->data[$i];
346
        }
347
348
        // Bail out with error if the sum is 0
349
        if ($sum == 0) {
350
            Util\JpGraphError::RaiseL(15009);
351
        }
352
        //("Illegal pie plot. Sum of all data is zero for Pie!");
353
354
        // Make sure we don't plot more values than data points
355
        // (in case the user added more legends than data points)
356
        $n = min(count($this->legends), count($this->data));
357
        if ($this->legends != "") {
358
            $this->legends = array_reverse(array_slice($this->legends, 0, $n));
359
        }
360
        for ($i = $n - 1; $i >= 0; --$i) {
361
            $l = $this->legends[$i];
362
            // Replace possible format with actual values
363
            if (count($this->csimalts) > $i) {
364
                $fmt = $this->csimalts[$i];
365
            } else {
366
                $fmt = "%d"; // Deafult Alt if no other has been specified
367
            }
368
            if ($this->labeltype == 0) {
369
                $l   = sprintf($l, 100 * $this->data[$i] / $sum);
370
                $alt = sprintf($fmt, $this->data[$i]);
371
            } elseif ($this->labeltype == 1) {
372
                $l   = sprintf($l, $this->data[$i]);
373
                $alt = sprintf($fmt, $this->data[$i]);
374
            } else {
375
                $l   = sprintf($l, $this->adjusted_data[$i]);
376
                $alt = sprintf($fmt, $this->adjusted_data[$i]);
377
            }
378
379
            if (empty($this->csimwintargets[$i])) {
380
                $wintarg = '';
381
            } else {
382
                $wintarg = $this->csimwintargets[$i];
383
            }
384
385
            if ($this->setslicecolors == null) {
386
                $graph->legend->Add($l, $colors[$ta[$i % $numcolors]], "", 0, $this->csimtargets[$i], $alt, $wintarg);
387
            } else {
388
                $graph->legend->Add($l, $this->setslicecolors[$i % $numcolors], "", 0, $this->csimtargets[$i], $alt, $wintarg);
389
            }
390
        }
391
    }
392
393
    // Adjust the rounded percetage value so that the sum of
394
    // of the pie slices are always 100%
395
    // Using the Hare/Niemeyer method
396
    public function AdjPercentage($aData, $aPrec = 0)
397
    {
398
        $mul = 100;
399
        if ($aPrec > 0 && $aPrec < 3) {
400
            if ($aPrec == 1) {
401
                $mul = 1000;
402
            } else {
403
                $mul = 10000;
404
            }
405
        }
406
407
        $tmp       = array();
408
        $result    = array();
409
        $quote_sum = 0;
410
        $n         = count($aData);
411
        for ($i = 0, $sum = 0; $i < $n; ++$i) {
412
            $sum += $aData[$i];
413
        }
414
415
        foreach ($aData as $index => $value) {
416
            $tmp_percentage = $value / $sum * $mul;
417
            $result[$index] = floor($tmp_percentage);
418
            $tmp[$index]    = $tmp_percentage - $result[$index];
419
            $quote_sum += $result[$index];
420
        }
421
        if ($quote_sum == $mul) {
422 View Code Duplication
            if ($mul > 100) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
423
                $tmp = $mul / 100;
424
                for ($i = 0; $i < $n; ++$i) {
425
                    $result[$i] /= $tmp;
426
                }
427
            }
428
            return $result;
429
        }
430
        arsort($tmp, SORT_NUMERIC);
431
        reset($tmp);
432
        for ($i = 0; $i < $mul - $quote_sum; $i++) {
433
            $result[key($tmp)]++;
434
            next($tmp);
435
        }
436 View Code Duplication
        if ($mul > 100) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
437
            $tmp = $mul / 100;
438
            for ($i = 0; $i < $n; ++$i) {
439
                $result[$i] /= $tmp;
440
            }
441
        }
442
        return $result;
443
    }
444
445
    public function Stroke($img, $aaoption = 0)
446
    {
447
        // aaoption is used to handle antialias
448
        // aaoption == 0 a normal pie
449
        // aaoption == 1 just the body
450
        // aaoption == 2 just the values
451
452
        // Explode scaling. If anti alias we scale the image
453
        // twice and we also need to scale the exploding distance
454
        $expscale = $aaoption === 1 ? 2 : 1;
455
456
        if ($this->labeltype == 2) {
457
            // Adjust the data so that it will add up to 100%
458
            $this->adjusted_data = $this->AdjPercentage($this->data);
459
        }
460
461
        if ($this->use_plot_theme_colors) {
462
            $this->setslicecolors = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $setslicecolors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
463
        }
464
465
        $colors = array_keys($img->rgb->rgb_table);
466
        sort($colors);
467
        $ta = $this->themearr[$this->theme];
468
        $n  = count($this->data);
469
470
        if ($this->setslicecolors == null) {
471
            $numcolors = count($ta);
472
        } else {
473
            // We need to create an array of colors as long as the data
474
            // since we need to reverse it to get the colors in the right order
475
            $numcolors = count($this->setslicecolors);
476
            $i         = 2 * $numcolors;
477
            while ($n > $i) {
478
                $this->setslicecolors = array_merge($this->setslicecolors, $this->setslicecolors);
479
                $i += $n;
480
            }
481
            $tt                   = array_slice($this->setslicecolors, 0, $n % $numcolors);
482
            $this->setslicecolors = array_merge($this->setslicecolors, $tt);
483
            $this->setslicecolors = array_reverse($this->setslicecolors);
484
        }
485
486
        // Draw the slices
487
        $sum = 0;
488
        for ($i = 0; $i < $n; ++$i) {
489
            $sum += $this->data[$i];
490
        }
491
492
        // Bail out with error if the sum is 0
493
        if ($sum == 0) {
494
            Util\JpGraphError::RaiseL(15009); //("Sum of all data is 0 for Pie.");
495
        }
496
497
        // Set up the pie-circle
498
        if ($this->radius <= 1) {
499
            $radius = floor($this->radius * min($img->width, $img->height));
500
        } else {
501
            $radius = $aaoption === 1 ? $this->radius * 2 : $this->radius;
502
        }
503
504 View Code Duplication
        if ($this->posx <= 1 && $this->posx > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
505
            $xc = round($this->posx * $img->width);
506
        } else {
507
            $xc = $this->posx;
508
        }
509
510 View Code Duplication
        if ($this->posy <= 1 && $this->posy > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
511
            $yc = round($this->posy * $img->height);
512
        } else {
513
            $yc = $this->posy;
514
        }
515
516
        $n = count($this->data);
517
518 View Code Duplication
        if ($this->explode_all) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
519
            for ($i = 0; $i < $n; ++$i) {
520
                $this->explode_radius[$i] = $this->explode_r;
521
            }
522
        }
523
524
        // If we have a shadow and not just drawing the labels
525
        if ($this->ishadowcolor != "" && $aaoption !== 2) {
526
            $accsum = 0;
527
            $angle2 = $this->startangle;
528
            $img->SetColor($this->ishadowcolor);
529
            for ($i = 0; $sum > 0 && $i < $n; ++$i) {
530
                $j      = $n - $i - 1;
531
                $d      = $this->data[$i];
532
                $angle1 = $angle2;
533
                $accsum += $d;
534
                $angle2 = $this->startangle + 2 * M_PI * $accsum / $sum;
535
                if (empty($this->explode_radius[$j])) {
536
                    $this->explode_radius[$j] = 0;
537
                }
538
539
                if ($d < 0.00001) {
540
                    continue;
541
                }
542
543
                $la = 2 * M_PI - (abs($angle2 - $angle1) / 2.0 + $angle1);
544
545
                $xcm = $xc + $this->explode_radius[$j] * cos($la) * $expscale;
546
                $ycm = $yc - $this->explode_radius[$j] * sin($la) * $expscale;
547
548
                $xcm += $this->ishadowdrop * $expscale;
549
                $ycm += $this->ishadowdrop * $expscale;
550
551
                $_sa = round($angle1 * 180 / M_PI);
552
                $_ea = round($angle2 * 180 / M_PI);
553
554
                // The CakeSlice method draws a full circle in case of start angle = end angle
555
                // for pie slices we don't want this behaviour unless we only have one
556
                // slice in the pie in case it is the wanted behaviour
557
                if ($_ea - $_sa > 0.1 || $n == 1) {
558
                    $img->CakeSlice($xcm, $ycm, $radius - 1, $radius - 1,
559
                        $angle1 * 180 / M_PI, $angle2 * 180 / M_PI, $this->ishadowcolor);
560
                }
561
            }
562
        }
563
564
        //--------------------------------------------------------------------------------
565
        // This is the main loop to draw each cake slice
566
        //--------------------------------------------------------------------------------
567
568
        // Set up the accumulated sum, start angle for first slice and border color
569
        $accsum = 0;
570
        $angle2 = $this->startangle;
571
        $img->SetColor($this->color);
572
573
        // Loop though all the slices if there is a pie to draw (sum>0)
574
        // There are n slices in total
575
        for ($i = 0; $sum > 0 && $i < $n; ++$i) {
576
577
            // $j is the actual index used for the slice
578
            $j = $n - $i - 1;
579
580
            // Make sure we havea  valid distance to explode the slice
581
            if (empty($this->explode_radius[$j])) {
582
                $this->explode_radius[$j] = 0;
583
            }
584
585
            // The actual numeric value for the slice
586
            $d = $this->data[$i];
587
588
            $angle1 = $angle2;
589
590
            // Accumlate the sum
591
            $accsum += $d;
592
593
            // The new angle when we add the "size" of this slice
594
            // angle1 is then the start and angle2 the end of this slice
595
            $angle2 = $this->NormAngle($this->startangle + 2 * M_PI * $accsum / $sum);
596
597
            // We avoid some trouble by not allowing end angle to be 0, in that case
598
            // we translate to 360
599
600
            // la is used to hold the label angle, which is centered on the slice
601
            if ($angle2 < 0.0001 && $angle1 > 0.0001) {
602
                $this->la[$i] = 2 * M_PI - (abs(2 * M_PI - $angle1) / 2.0 + $angle1);
603
            } elseif ($angle1 > $angle2) {
604
                // The case where the slice crosses the 3 a'clock line
605
                // Remember that the slices are counted clockwise and
606
                // labels are counted counter clockwise so we need to revert with 2 PI
607
                $this->la[$i] = 2 * M_PI - $this->NormAngle($angle1 + ((2 * M_PI - $angle1) + $angle2) / 2);
608
            } else {
609
                $this->la[$i] = 2 * M_PI - (abs($angle2 - $angle1) / 2.0 + $angle1);
610
            }
611
612
            // Too avoid rounding problems we skip the slice if it is too small
613
            if ($d < 0.00001) {
614
                continue;
615
            }
616
617
            // If the user has specified an array of colors for each slice then use
618
            // that a color otherwise use the theme array (ta) of colors
619
            if ($this->setslicecolors == null) {
620
                $slicecolor = $colors[$ta[$i % $numcolors]];
621
            } else {
622
                $slicecolor = $this->setslicecolors[$i % $numcolors];
623
            }
624
625
            //            $_sa = round($angle1*180/M_PI);
1 ignored issue
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
626
            //            $_ea = round($angle2*180/M_PI);
1 ignored issue
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
627
            //            $_la = round($this->la[$i]*180/M_PI);
1 ignored issue
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
628
            //            echo "Slice#$i: ang1=$_sa , ang2=$_ea, la=$_la, color=$slicecolor<br>";
629
630
            // If we have enabled antialias then we don't draw any border so
631
            // make the bordedr color the same as the slice color
632
            if ($this->pie_interior_border && $aaoption === 0) {
633
                $img->SetColor($this->color);
634
            } else {
635
                $img->SetColor($slicecolor);
636
            }
637
            $arccolor = $this->pie_border && $aaoption === 0 ? $this->color : "";
638
639
            // Calculate the x,y coordinates for the base of this slice taking
640
            // the exploded distance into account. Here we use the mid angle as the
641
            // ray of extension and we have the mid angle handy as it is also the
642
            // label angle
643
            $xcm = $xc + $this->explode_radius[$j] * cos($this->la[$i]) * $expscale;
644
            $ycm = $yc - $this->explode_radius[$j] * sin($this->la[$i]) * $expscale;
645
646
            // If we are not just drawing the labels then draw this cake slice
647
            if ($aaoption !== 2) {
648
                $_sa = round($angle1 * 180 / M_PI);
649
                $_ea = round($angle2 * 180 / M_PI);
650
                $_la = round($this->la[$i] * 180 / M_PI);
0 ignored issues
show
Unused Code introduced by
$_la is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
651
                //echo "[$i] sa=$_sa, ea=$_ea, la[$i]=$_la, (color=$slicecolor)<br>";
652
653
                // The CakeSlice method draws a full circle in case of start angle = end angle
654
                // for pie slices we want this in case the slice have a value larger than 99% of the
655
                // total sum
656
                if (abs($_ea - $_sa) >= 1 || $d == $sum) {
657
                    $img->CakeSlice($xcm, $ycm, $radius - 1, $radius - 1, $_sa, $_ea, $slicecolor, $arccolor);
658
                }
659
            }
660
661
            // If the CSIM is used then make sure we register a CSIM area for this slice as well
662
            if ($this->csimtargets && $aaoption !== 1) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->csimtargets of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
663
                $this->AddSliceToCSIM($i, $xcm, $ycm, $radius, $angle1, $angle2);
664
            }
665
        }
666
667
        // Format the titles for each slice
668
        if ($aaoption !== 2) {
669
            for ($i = 0; $i < $n; ++$i) {
670
                if ($this->labeltype == 0) {
671 View Code Duplication
                    if ($sum != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
672
                        $l = 100.0 * $this->data[$i] / $sum;
673
                    } else {
674
                        $l = 0.0;
675
                    }
676
                } elseif ($this->labeltype == 1) {
677
                    $l = $this->data[$i] * 1.0;
678
                } else {
679
                    $l = $this->adjusted_data[$i];
680
                }
681
                if (isset($this->labels[$i]) && is_string($this->labels[$i])) {
682
                    $this->labels[$i] = sprintf($this->labels[$i], $l);
683
                } else {
684
                    $this->labels[$i] = $l;
685
                }
686
            }
687
        }
688
689
        if ($this->value->show && $aaoption !== 1) {
690
            $this->StrokeAllLabels($img, $xc, $yc, $radius);
691
        }
692
693
        // Adjust title position
694 View Code Duplication
        if ($aaoption !== 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
695
            $this->title->SetPos($xc,
696
                $yc - $this->title->GetFontHeight($img) - $radius - $this->title->margin,
0 ignored issues
show
Bug introduced by
The property margin does not seem to exist. Did you mean _margin?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
697
                "center", "bottom");
698
            $this->title->Stroke($img);
699
        }
700
    }
701
702
    //---------------
703
    // PRIVATE METHODS
704
705
    public function NormAngle($a)
706
    {
707
        while ($a < 0) {
708
            $a += 2 * M_PI;
709
        }
710
711
        while ($a > 2 * M_PI) {
712
            $a -= 2 * M_PI;
713
        }
714
715
        return $a;
716
    }
717
718
    public function Quadrant($a)
719
    {
720
        $a = $this->NormAngle($a);
721
        if ($a > 0 && $a <= M_PI / 2) {
722
            return 0;
723
        }
724
725
        if ($a > M_PI / 2 && $a <= M_PI) {
726
            return 1;
727
        }
728
729
        if ($a > M_PI && $a <= 1.5 * M_PI) {
730
            return 2;
731
        }
732
733
        if ($a > 1.5 * M_PI) {
734
            return 3;
735
        }
736
    }
737
738
    public function StrokeGuideLabels($img, $xc, $yc, $radius)
739
    {
740
        $n = count($this->labels);
741
742
        //-----------------------------------------------------------------------
743
        // Step 1 of the algorithm is to construct a number of clusters
744
        // a cluster is defined as all slices within the same quadrant (almost)
745
        // that has an angular distance less than the treshold
746
        //-----------------------------------------------------------------------
747
        $tresh_hold = 25 * M_PI / 180; // 25 degrees difference to be in a cluster
748
        $incluster  = false; // flag if we are currently in a cluster or not
749
        $clusters   = array(); // array of clusters
750
        $cidx       = -1; // running cluster index
751
752
        // Go through all the labels and construct a number of clusters
753
        for ($i = 0; $i < $n - 1; ++$i) {
754
            // Calc the angle distance between two consecutive slices
755
            $a1   = $this->la[$i];
756
            $a2   = $this->la[$i + 1];
757
            $q1   = $this->Quadrant($a1);
758
            $q2   = $this->Quadrant($a2);
759
            $diff = abs($a1 - $a2);
760
            if ($diff < $tresh_hold) {
761
                if ($incluster) {
762
                    $clusters[$cidx][1]++;
763
                    // Each cluster can only cover one quadrant
764
                    // Do we cross a quadrant ( and must break the cluster)
765
                    if ($q1 != $q2) {
766
                        // If we cross a quadrant boundary we normally start a
767
                        // new cluster. However we need to take the 12'a clock
768
                        // and 6'a clock positions into a special consideration.
769
                        // Case 1: WE go from q=1 to q=2 if the last slice on
770
                        // the cluster for q=1 is close to 12'a clock and the
771
                        // first slice in q=0 is small we extend the previous
772
                        // cluster
773
                        if ($q1 == 1 && $q2 == 0 && $a2 > (90 - 15) * M_PI / 180) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $q2 of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
774 View Code Duplication
                            if ($i < $n - 2) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
775
                                $a3 = $this->la[$i + 2];
776
                                // If there isn't a cluster coming up with the next-next slice
777
                                // we extend the previous cluster to cover this slice as well
778
                                if (abs($a3 - $a2) >= $tresh_hold) {
779
                                    $clusters[$cidx][1]++;
780
                                    $i++;
781
                                }
782
                            }
783
                        } elseif ($q1 == 3 && $q2 == 2 && $a2 > (270 - 15) * M_PI / 180) {
784 View Code Duplication
                            if ($i < $n - 2) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
785
                                $a3 = $this->la[$i + 2];
786
                                // If there isn't a cluster coming up with the next-next slice
787
                                // we extend the previous cluster to cover this slice as well
788
                                if (abs($a3 - $a2) >= $tresh_hold) {
789
                                    $clusters[$cidx][1]++;
790
                                    $i++;
791
                                }
792
                            }
793
                        }
794
795
                        if ($q1 == 2 && $q2 == 1 && $a2 > (180 - 15) * M_PI / 180) {
796
                            $clusters[$cidx][1]++;
797
                            $i++;
798
                        }
799
800
                        $incluster = false;
801
                    }
802
                } elseif ($q1 == $q2) {
803
                    $incluster = true;
804
                    // Now we have a special case for quadrant 0. If we previously
805
                    // have a cluster of one in quadrant 0 we just extend that
806
                    // cluster. If we don't do this then we risk that the label
807
                    // for the cluster of one will cross the guide-line
808
                    if ($q1 == 0 && $cidx > -1 &&
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $q1 of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
809
                        $clusters[$cidx][1] == 1 &&
810
                        $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->Quadrant($this->la[$clusters[$cidx][0]]) of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
811
                        $clusters[$cidx][1]++;
812
                    } else {
813
                        $cidx++;
814
                        $clusters[$cidx][0] = $i;
815
                        $clusters[$cidx][1] = 1;
816
                    }
817
                } else {
818
                    // Create a "cluster" of one since we are just crossing
819
                    // a quadrant
820
                    $cidx++;
821
                    $clusters[$cidx][0] = $i;
822
                    $clusters[$cidx][1] = 1;
823
                }
824 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
825
                if ($incluster) {
826
                    // Add the last slice
827
                    $clusters[$cidx][1]++;
828
                    $incluster = false;
829
                } else {
830
                    // Create a "cluster" of one
831
                    $cidx++;
832
                    $clusters[$cidx][0] = $i;
833
                    $clusters[$cidx][1] = 1;
834
                }
835
            }
836
        }
837
        // Handle the very last slice
838 View Code Duplication
        if ($incluster) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
839
            $clusters[$cidx][1]++;
840
        } else {
841
            // Create a "cluster" of one
842
            $cidx++;
843
            $clusters[$cidx][0] = $i;
844
            $clusters[$cidx][1] = 1;
845
        }
846
847
        /*
1 ignored issue
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
848
        if( true ) {
849
        // Debug printout in labels
850
        for( $i=0; $i <= $cidx; ++$i ) {
851
        for( $j=0; $j < $clusters[$i][1]; ++$j ) {
852
        $a = $this->la[$clusters[$i][0]+$j];
853
        $aa = round($a*180/M_PI);
854
        $q = $this->Quadrant($a);
855
        $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j";
856
        }
857
        }
858
        }
859
         */
860
861
        //-----------------------------------------------------------------------
862
        // Step 2 of the algorithm is use the clusters and draw the labels
863
        // and guidelines
864
        //-----------------------------------------------------------------------
865
866
        // We use the font height as the base factor for how far we need to
867
        // spread the labels in the Y-direction.
868
        $this->value->ApplyFont($img);
869
        $fh        = $img->GetFontHeight();
870
        $origvstep = $fh * $this->iGuideVFactor;
871
        $this->value->SetMargin(0);
872
873
        // Number of clusters found
874
        $nc = count($clusters);
875
876
        // Walk through all the clusters
877
        for ($i = 0; $i < $nc; ++$i) {
878
879
            // Start angle and number of slices in this cluster
880
            $csize = $clusters[$i][1];
881
            $a     = $this->la[$clusters[$i][0]];
882
            $q     = $this->Quadrant($a);
883
884
            // Now set up the start and end conditions to make sure that
885
            // in each cluster we walk through the all the slices starting with the slice
886
            // closest to the equator. Since all slices are numbered clockwise from "3'a clock"
887
            // we have different conditions depending on in which quadrant the slice lies within.
888
            if ($q == 0) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $q of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
889
                $start = $csize - 1;
890
                $idx   = $start;
891
                $step  = -1;
892
                $vstep = -$origvstep;
893 View Code Duplication
            } elseif ($q == 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
894
                $start = 0;
895
                $idx   = $start;
896
                $step  = 1;
897
                $vstep = -$origvstep;
898
            } elseif ($q == 2) {
899
                $start = $csize - 1;
900
                $idx   = $start;
901
                $step  = -1;
902
                $vstep = $origvstep;
903 View Code Duplication
            } elseif ($q == 3) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
904
                $start = 0;
905
                $idx   = $start;
906
                $step  = 1;
907
                $vstep = $origvstep;
908
            }
909
910
            // Walk through all slices within this cluster
911
            for ($j = 0; $j < $csize; ++$j) {
912
                // Now adjust the position of the labels in each cluster starting
913
                // with the slice that is closest to the equator of the pie
914
                $a = $this->la[$clusters[$i][0] + $idx];
0 ignored issues
show
Bug introduced by
The variable $idx does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
915
916
                // Guide line start in the center of the arc of the slice
917
                $r = $radius + $this->explode_radius[$n - 1 - ($clusters[$i][0] + $idx)];
918
                $x = round($r * cos($a) + $xc);
919
                $y = round($yc - $r * sin($a));
920
921
                // The distance from the arc depends on chosen font and the "R-Factor"
922
                $r += $fh * $this->iGuideLineRFactor;
923
924
                // Should the labels be placed curved along the pie or in straight columns
925
                // outside the pie?
926
                if ($this->iGuideLineCurve) {
927
                    $xt = round($r * cos($a) + $xc);
928
                }
929
930
                // If this is the first slice in the cluster we need some first time
931
                // proessing
932
                if ($idx == $start) {
0 ignored issues
show
Bug introduced by
The variable $start does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
933
                    if (!$this->iGuideLineCurve) {
934
                        $xt = round($r * cos($a) + $xc);
935
                    }
936
937
                    $yt = round($yc - $r * sin($a));
938
939
                    // Some special consideration in case this cluster starts
940
                    // in quadrant 1 or 3 very close to the "equator" (< 20 degrees)
941
                    // and the previous clusters last slice is within the tolerance.
942
                    // In that case we add a font height to this labels Y-position
943
                    // so it doesn't collide with
944
                    // the slice in the previous cluster
945
                    $prevcluster = ($i + ($nc - 1)) % $nc;
946
                    $previdx     = $clusters[$prevcluster][0] + $clusters[$prevcluster][1] - 1;
947
                    if ($q == 1 && $a > 160 * M_PI / 180) {
948
                        // Get the angle for the previous clusters last slice
949
                        $diff = abs($a - $this->la[$previdx]);
950
                        if ($diff < $tresh_hold) {
951
                            $yt -= $fh;
952
                        }
953
                    } elseif ($q == 3 && $a > 340 * M_PI / 180) {
954
                        // We need to subtract 360 to compare angle distance between
955
                        // q=0 and q=3
956
                        $diff = abs($a - $this->la[$previdx] - 360 * M_PI / 180);
957
                        if ($diff < $tresh_hold) {
958
                            $yt += $fh;
959
                        }
960
                    }
961
                } else {
962
                    // The step is at minimum $vstep but if the slices are relatively large
963
                    // we make sure that we add at least a step that corresponds to the vertical
964
                    // distance between the centers at the arc on the slice
965
                    $prev_a = $this->la[$clusters[$i][0] + ($idx - $step)];
0 ignored issues
show
Bug introduced by
The variable $step does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
966
                    $dy     = abs($radius * (sin($a) - sin($prev_a)) * 1.2);
967
                    if ($vstep > 0) {
968
                        $yt += max($vstep, $dy);
0 ignored issues
show
Bug introduced by
The variable $yt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $vstep does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
969
                    } else {
970
                        $yt += min($vstep, -$dy);
971
                    }
972
                }
973
974
                $label = $this->labels[$clusters[$i][0] + $idx];
975
976
                if ($csize == 1) {
977
                    // A "meta" cluster with only one slice
978
                    $r  = $radius + $this->explode_radius[$n - 1 - ($clusters[$i][0] + $idx)];
979
                    $rr = $r + $img->GetFontHeight() / 2;
980
                    $xt = round($rr * cos($a) + $xc);
981
                    $yt = round($yc - $rr * sin($a));
982
                    $this->StrokeLabel($label, $img, $xc, $yc, $a, $r);
983
                    if ($this->iShowGuideLineForSingle) {
984
                        $this->guideline->Stroke($img, $x, $y, $xt, $yt);
985
                    }
986
                } else {
987
                    $this->guideline->Stroke($img, $x, $y, $xt, $yt);
0 ignored issues
show
Bug introduced by
The variable $xt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
988
                    if ($q == 1 || $q == 2) {
989
                        // Left side of Pie
990
                        $this->guideline->Stroke($img, $xt, $yt, $xt - $this->guidelinemargin, $yt);
991
                        $lbladj              = -$this->guidelinemargin - 5;
992
                        $this->value->halign = "right";
993
                        $this->value->valign = "center";
994
                    } else {
995
                        // Right side of pie
996
                        $this->guideline->Stroke($img, $xt, $yt, $xt + $this->guidelinemargin, $yt);
997
                        $lbladj              = $this->guidelinemargin + 5;
998
                        $this->value->halign = "left";
999
                        $this->value->valign = "center";
1000
                    }
1001
                    $this->value->Stroke($img, $label, $xt + $lbladj, $yt);
1002
                }
1003
1004
                // Udate idx to point to next slice in the cluster to process
1005
                $idx += $step;
1006
            }
1007
        }
1008
    }
1009
1010
    public function StrokeAllLabels($img, $xc, $yc, $radius)
1011
    {
1012
        // First normalize all angles for labels
1013
        $n = count($this->la);
1014
        for ($i = 0; $i < $n; ++$i) {
1015
            $this->la[$i] = $this->NormAngle($this->la[$i]);
1016
        }
1017
        if ($this->guideline->iShow) {
1018
            $this->StrokeGuideLabels($img, $xc, $yc, $radius);
1019
        } else {
1020
            $n = count($this->labels);
1021
            for ($i = 0; $i < $n; ++$i) {
1022
                $this->StrokeLabel($this->labels[$i], $img, $xc, $yc,
1023
                    $this->la[$i],
1024
                    $radius + $this->explode_radius[$n - 1 - $i]);
1025
            }
1026
        }
1027
    }
1028
1029
    // Position the labels of each slice
1030
    public function StrokeLabel($label, $img, $xc, $yc, $a, $r)
1031
    {
1032
1033
        // Default value
1034
        if ($this->ilabelposadj === 'auto') {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->ilabelposadj (integer) and 'auto' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1035
            $this->ilabelposadj = 0.65;
0 ignored issues
show
Documentation Bug introduced by
The property $ilabelposadj was declared of type integer, but 0.65 is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1036
        }
1037
1038
        // We position the values diferently depending on if they are inside
1039
        // or outside the pie
1040
        if ($this->ilabelposadj < 1.0) {
1041
            $this->value->SetAlign('center', 'center');
1042
            $this->value->margin = 0;
1043
1044
            $xt = round($this->ilabelposadj * $r * cos($a) + $xc);
1045
            $yt = round($yc - $this->ilabelposadj * $r * sin($a));
1046
1047
            $this->value->Stroke($img, $label, $xt, $yt);
1048
        } else {
1049
            $this->value->halign = "left";
1050
            $this->value->valign = "top";
1051
            $this->value->margin = 0;
1052
1053
            // Position the axis title.
1054
            // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
1055
            // that intersects with the extension of the corresponding axis. The code looks a little
1056
            // bit messy but this is really the only way of having a reasonable position of the
1057
            // axis titles.
1058
            $this->value->ApplyFont($img);
1059
            $h = $img->GetTextHeight($label);
1060
            // For numeric values the format of the display value
1061
            // must be taken into account
1062 View Code Duplication
            if (is_numeric($label)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1063
                if ($label > 0) {
1064
                    $w = $img->GetTextWidth(sprintf($this->value->format, $label));
1065
                } else {
1066
                    $w = $img->GetTextWidth(sprintf($this->value->negformat, $label));
1067
                }
1068
            } else {
1069
                $w = $img->GetTextWidth($label);
1070
            }
1071
1072
            if ($this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) {
1073
                $r *= $this->ilabelposadj;
1074
            }
1075
1076
            $r += $img->GetFontHeight() / 1.5;
1077
1078
            $xt = round($r * cos($a) + $xc);
1079
            $yt = round($yc - $r * sin($a));
1080
1081
            // Normalize angle
1082
            while ($a < 0) {
1083
                $a += 2 * M_PI;
1084
            }
1085
1086
            while ($a > 2 * M_PI) {
1087
                $a -= 2 * M_PI;
1088
            }
1089
1090
            if ($a >= 7 * M_PI / 4 || $a <= M_PI / 4) {
1091
                $dx = 0;
1092
            }
1093
1094
            if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
1095
                $dx = ($a - M_PI / 4) * 2 / M_PI;
1096
            }
1097
1098
            if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
1099
                $dx = 1;
1100
            }
1101
1102
            if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
1103
                $dx = (1 - ($a - M_PI * 5 / 4) * 2 / M_PI);
1104
            }
1105
1106
            if ($a >= 7 * M_PI / 4) {
1107
                $dy = (($a - M_PI) - 3 * M_PI / 4) * 2 / M_PI;
1108
            }
1109
1110
            if ($a <= M_PI / 4) {
1111
                $dy = (1 - $a * 2 / M_PI);
1112
            }
1113
1114
            if ($a >= M_PI / 4 && $a <= 3 * M_PI / 4) {
1115
                $dy = 1;
1116
            }
1117
1118
            if ($a >= 3 * M_PI / 4 && $a <= 5 * M_PI / 4) {
1119
                $dy = (1 - ($a - 3 * M_PI / 4) * 2 / M_PI);
1120
            }
1121
1122
            if ($a >= 5 * M_PI / 4 && $a <= 7 * M_PI / 4) {
1123
                $dy = 0;
1124
            }
1125
1126
            $this->value->Stroke($img, $label, $xt - $dx * $w, $yt - $dy * $h);
0 ignored issues
show
Bug introduced by
The variable $dx does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $dy does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1127
        }
1128
    }
1129
1130
    public function UsePlotThemeColors($flag = true)
1131
    {
1132
        $this->use_plot_theme_colors = $flag;
1133
    }
1134
} // Class
1135
1136
/* EOF */
1137