Test Failed
Push — develop ( 48349f...3c7590 )
by Felipe
15:17
created

Scale::GetMinVal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * JPGraph v4.1.0-beta.01
5
 */
6
7
namespace Amenadiel\JpGraph\Graph\Scale;
8
9
use function abs;
10
use Amenadiel\JpGraph\Graph\Configs;
11
use Amenadiel\JpGraph\Util;
12
use function assert;
13
use function ceil;
14
use function floor;
15
use function is_numeric;
16
use function log10;
17
use function pow;
18
use function round;
19
20
/**
21
 * @class LinearScale
22
 * // Description: Handle linear scaling between screen and world
23
 */
24
class Scale extends Configs
25
{
26
    public $textscale = false; // Just a flag to let the Plot class find out if
27
    // we are a textscale or not. This is a cludge since
28
    // this information is available in Graph::axtype but
29
    // we don't have access to the graph object in the Plots
30
    // stroke method. So we let graph store the status here
31
    // when the linear scale is created. A real cludge...
32
    public $type; // is this x or y scale ?
33
    public $ticks; // Store ticks
34
    public $text_scale_off = 0;
35
    public $scale_abs      = [0, 0];
36
    public $scale_factor; // Scale factor between world and screen
37
    public $off; // Offset between image edge and plot area
38
    public $scale      = [0, 0];
39
    public $name       = 'lin';
40
    public $auto_ticks = false; // When using manual scale should the ticks be automatically set?
41
    public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php)
42
    public $intscale         = false; // Restrict autoscale to integers
43
    protected $autoscale_min = false; // Forced minimum value, auto determine max
44
    protected $autoscale_max = false; // Forced maximum value, auto determine min
45
    private $gracetop        = 0;
46
    private $gracebottom     = 0;
47
48
    private $_world_size; // Plot area size in world coordinates
49
50
    public function __construct($aMin = 0, $aMax = 0, $aType = 'y')
51
    {
52
        assert($aType == 'x' || $aType == 'y');
53
        assert($aMin <= $aMax);
54
55
        $this->type       = $aType;
56
        $this->scale      = [$aMin, $aMax];
57
        $this->world_size = $aMax - $aMin;
58
    }
59
    // get maximum value for scale
60
    public function GetMaxVal()
61
    {
62
        return $this->scale[1];
63
    }
64
    // Get the minimum value in the scale
65
    public function GetMinVal()
66
    {
67
        return $this->scale[0];
68
    }
69
    // Check if scale is set or if we should autoscale
70
    // We should do this is either scale or ticks has not been set
71
    public function IsSpecified()
72
    {
73
        if ($this->GetMinVal() == $this->GetMaxVal()) {
74
            // Scale not set
75
            return false;
76
        }
77
78
        return true;
79
    }
80
81
    // Initialize the conversion constants for this scale
82
    // This tries to pre-calculate as much as possible to speed up the
83
    // actual conversion (with Translate()) later on
84
    // $start =scale start in absolute pixels (for x-scale this is an y-position
85
    //     and for an y-scale this is an x-position
86
    // $len   =absolute length in pixels of scale
87
    public function SetConstants($aStart, $aLen)
88
    {
89
        $this->world_abs_size = $aLen;
90
        $this->off            = $aStart;
91
92
        if ($this->world_size <= 0) {
93
            // This should never ever happen !!
94
            Util\JpGraphError::RaiseL(25074);
95
            //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to [email protected] and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail.");
96
        }
97
98
        // scale_factor = number of pixels per world unit
99
        $this->scale_factor = $this->world_abs_size / ($this->world_size * 1.0);
100
101
        // scale_abs = start and end points of scale in absolute pixels
102
        $this->scale_abs = [$this->off, $this->off + $this->world_size * $this->scale_factor];
103
    }
104
105
    // Calculate an integer autoscale
106
    public function IntAutoScale($img, $min, $max, $maxsteps, $majend = true)
107
    {
108
        // Make sure limits are integers
109
        $min = floor($min);
110
        $max = ceil($max);
111
        if (abs($min - $max) == 0) {
112
            --$min;
113
            ++$max;
114
        }
115
        $maxsteps = floor($maxsteps);
116
117
        $gracetop    = round(($this->gracetop / 100.0) * abs($max - $min));
118
        $gracebottom = round(($this->gracebottom / 100.0) * abs($max - $min));
119
        if (is_numeric($this->autoscale_min)) {
0 ignored issues
show
introduced by
The condition is_numeric($this->autoscale_min) is always false.
Loading history...
120
            $min = ceil($this->autoscale_min);
121
            if ($min >= $max) {
122
                Util\JpGraphError::RaiseL(25071); //('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
123
            }
124
        }
125
126
        if (is_numeric($this->autoscale_max)) {
0 ignored issues
show
introduced by
The condition is_numeric($this->autoscale_max) is always false.
Loading history...
127
            $max = ceil($this->autoscale_max);
128
            if ($min >= $max) {
129
                Util\JpGraphError::RaiseL(25072); //('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
130
            }
131
        }
132
133
        if (abs($min - $max) == 0) {
134
            ++$max;
135
            --$min;
136
        }
137
138
        $min -= $gracebottom;
139
        $max += $gracetop;
140
141
        // First get tickmarks as multiples of 1, 10, ...
142
        if ($majend) {
143
            list($num1steps, $adj1min, $adj1max, $maj1step) = $this->IntCalcTicks($maxsteps, $min, $max, 1);
144
        } else {
145
            $adj1min                    = $min;
146
            $adj1max                    = $max;
147
            list($num1steps, $maj1step) = $this->IntCalcTicksFreeze($maxsteps, $min, $max, 1);
148
        }
149
150
        if (abs($min - $max) > 2) {
151
            // Then get tick marks as 2:s 2, 20, ...
152
            if ($majend) {
153
                list($num2steps, $adj2min, $adj2max, $maj2step) = $this->IntCalcTicks($maxsteps, $min, $max, 5);
154
            } else {
155
                $adj2min                    = $min;
156
                $adj2max                    = $max;
157
                list($num2steps, $maj2step) = $this->IntCalcTicksFreeze($maxsteps, $min, $max, 5);
158
            }
159
        } else {
160
            $num2steps = 10000; // Dummy high value so we don't choose this
161
        }
162
163
        if (abs($min - $max) > 5) {
164
            // Then get tickmarks as 5:s 5, 50, 500, ...
165
            if ($majend) {
166
                list($num5steps, $adj5min, $adj5max, $maj5step) = $this->IntCalcTicks($maxsteps, $min, $max, 2);
167
            } else {
168
                $adj5min                    = $min;
169
                $adj5max                    = $max;
170
                list($num5steps, $maj5step) = $this->IntCalcTicksFreeze($maxsteps, $min, $max, 2);
171
            }
172
        } else {
173
            $num5steps = 10000; // Dummy high value so we don't choose this
174
        }
175
176
        // Check to see whichof 1:s, 2:s or 5:s fit better with
177
        // the requested number of major ticks
178
        $match1 = abs($num1steps - $maxsteps);
179
        $match2 = abs($num2steps - $maxsteps);
180
        if (!empty($maj5step) && $maj5step > 1) {
181
            $match5 = abs($num5steps - $maxsteps);
182
        } else {
183
            $match5 = 10000; // Dummy high value
184
        }
185
186
        // Compare these three values and see which is the closest match
187
        // We use a 0.6 weight to gravitate towards multiple of 5:s
188
        if ($match1 < $match2) {
189
            if ($match1 < $match5) {
190
                $r = 1;
191
            } else {
192
                $r = 3;
193
            }
194
        } else {
195
            if ($match2 < $match5) {
196
                $r = 2;
197
            } else {
198
                $r = 3;
199
            }
200
        }
201
        // Minsteps are always the same as maxsteps for integer scale
202
        switch ($r) {
203
            case 1:
204
                $this->ticks->Set($maj1step, $maj1step);
205
                $this->Update($img, $adj1min, $adj1max);
206
207
                break;
208
            case 2:
209
                $this->ticks->Set($maj2step, $maj2step);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $maj2step does not seem to be defined for all execution paths leading up to this point.
Loading history...
210
                $this->Update($img, $adj2min, $adj2max);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $adj2max does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $adj2min does not seem to be defined for all execution paths leading up to this point.
Loading history...
211
212
                break;
213
            case 3:
214
                $this->ticks->Set($maj5step, $maj5step);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $maj5step does not seem to be defined for all execution paths leading up to this point.
Loading history...
215
                $this->Update($img, $adj5min, $adj5max);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $adj5min does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $adj5max does not seem to be defined for all execution paths leading up to this point.
Loading history...
216
217
                break;
218
            default:
219
                Util\JpGraphError::RaiseL(25073, $r); //('Internal error. Integer scale algorithm comparison out of bound (r=$r)');
220
        }
221
    }
222
223
    // Specify a new min/max value for sclae
224
    public function Update($aImg, $aMin, $aMax)
225
    {
226
        $this->scale      = [$aMin, $aMax];
227
        $this->world_size = $aMax - $aMin;
228
        $this->InitConfigs($aImg);
229
    }
230
    /**
231
     * PRIVATE METHODS.
232
     *
233
     * @param mixed $img
234
     */
235
236
    // This method recalculates all constants that are depending on the
237
    // margins in the image. If the margins in the image are changed
238
    // this method should be called for every scale that is registred with
239
    // that image. Should really be installed as an observer of that image.
240
    public function InitConfigs($img)
241
    {
242
        if ($this->type == 'x') {
243
            $this->world_abs_size = $img->width - $img->left_margin - $img->right_margin;
244
            $this->off            = $img->left_margin;
245
            $this->scale_factor   = 0;
246
            if ($this->world_size > 0) {
247
                $this->scale_factor = $this->world_abs_size / ($this->world_size * 1.0);
248
            }
249
        } else {
250
            // y scale
251
            $this->world_abs_size = $img->height - $img->top_margin - $img->bottom_margin;
252
            $this->off            = $img->top_margin + $this->world_abs_size;
253
            $this->scale_factor   = 0;
254
            if ($this->world_size > 0) {
255
                $this->scale_factor = -$this->world_abs_size / ($this->world_size * 1.0);
256
            }
257
        }
258
        $size            = $this->world_size * $this->scale_factor;
259
        $this->scale_abs = [$this->off, $this->off + $size];
260
    }
261
262
    // Initialize the conversion constants for this scale
263
    // This tries to pre-calculate as much as possible to speed up the
264
    // actual conversion (with Translate()) later on
265
    // $start =scale start in absolute pixels (for x-scale this is an y-position
266
    //     and for an y-scale this is an x-position
267
    // $len   =absolute length in pixels of scale
268
    public function SetConfigs($aStart, $aLen)
269
    {
270
        $this->world_abs_size = $aLen;
271
        $this->off            = $aStart;
272
273
        if ($this->world_size <= 0) {
274
            // This should never ever happen !!
275
            Util\JpGraphError::RaiseL(25074);
276
            //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to [email protected] and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail.");
277
        }
278
279
        // scale_factor = number of pixels per world unit
280
        $this->scale_factor = $this->world_abs_size / ($this->world_size * 1.0);
281
282
        // scale_abs = start and end points of scale in absolute pixels
283
        $this->scale_abs = [$this->off, $this->off + $this->world_size * $this->scale_factor];
284
    }
285
286
    // Calculate number of ticks steps with a specific division
287
    // $a is the divisor of 10**x to generate the first maj tick intervall
288
    // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,...
289
    // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,...
290
    // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,...
291
    // We return a vector of
292
    //  [$numsteps,$adjmin,$adjmax,$minstep,$majstep]
293
    // If $majend==true then the first and last marks on the axis will be major
294
    // labeled tick marks otherwise it will be adjusted to the closest min tick mark
295
    public function CalcTicks($maxsteps, $min, $max, $a, $b, $majend = true)
296
    {
297
        $diff = $max - $min;
298
        if ($diff == 0) {
299
            $ld = 0;
300
        } else {
301
            $ld = floor(log10($diff));
302
        }
303
304
        // Gravitate min towards zero if we are close
305
        if ($min > 0 && $min < pow(10, $ld)) {
306
            $min = 0;
307
        }
308
309
        //$majstep=pow(10,$ld-1)/$a;
310
        $majstep = pow(10, $ld) / $a;
311
        $minstep = $majstep / $b;
312
313
        $adjmax   = ceil($max / $minstep) * $minstep;
314
        $adjmin   = floor($min / $minstep) * $minstep;
315
        $adjdiff  = $adjmax - $adjmin;
316
        $numsteps = $adjdiff / $majstep;
317
318
        while ($numsteps > $maxsteps) {
319
            $majstep  = pow(10, $ld) / $a;
320
            $numsteps = $adjdiff / $majstep;
321
            ++$ld;
322
        }
323
324
        $minstep = $majstep / $b;
325
        $adjmin  = floor($min / $minstep) * $minstep;
326
        $adjdiff = $adjmax - $adjmin;
0 ignored issues
show
Unused Code introduced by
The assignment to $adjdiff is dead and can be removed.
Loading history...
327
        if ($majend) {
328
            $adjmin  = floor($min / $majstep) * $majstep;
329
            $adjdiff = $adjmax - $adjmin;
330
            $adjmax  = ceil($adjdiff / $majstep) * $majstep + $adjmin;
331
        } else {
332
            $adjmax = ceil($max / $minstep) * $minstep;
333
        }
334
335
        return [$numsteps, $adjmin, $adjmax, $minstep, $majstep];
336
    }
337
338
    public function CalcTicksFreeze($maxsteps, $min, $max, $a, $b)
339
    {
340
        // Same as CalcTicks but don't adjust min/max values
341
        $diff = $max - $min;
342
        if ($diff == 0) {
343
            $ld = 0;
344
        } else {
345
            $ld = floor(log10($diff));
346
        }
347
348
        //$majstep=pow(10,$ld-1)/$a;
349
        $majstep  = pow(10, $ld) / $a;
350
        $minstep  = $majstep / $b;
0 ignored issues
show
Unused Code introduced by
The assignment to $minstep is dead and can be removed.
Loading history...
351
        $numsteps = floor($diff / $majstep);
352
353
        while ($numsteps > $maxsteps) {
354
            $majstep  = pow(10, $ld) / $a;
355
            $numsteps = floor($diff / $majstep);
356
            ++$ld;
357
        }
358
        $minstep = $majstep / $b;
359
360
        return [$numsteps, $minstep, $majstep];
361
    }
362
363
    public function IntCalcTicks($maxsteps, $min, $max, $a, $majend = true)
364
    {
365
        $diff = $max - $min;
366
        if ($diff == 0) {
367
            Util\JpGraphError::RaiseL(25075); //('Can\'t automatically determine ticks since min==max.');
368
        } else {
369
            $ld = floor(log10($diff));
370
        }
371
372
        // Gravitate min towards zero if we are close
373
        if ($min > 0 && $min < pow(10, $ld)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ld does not seem to be defined for all execution paths leading up to this point.
Loading history...
374
            $min = 0;
375
        }
376
        if ($ld == 0) {
377
            $ld = 1;
378
        }
379
        if ($a == 1) {
380
            $majstep = 1;
381
        } else {
382
            $majstep = pow(10, $ld) / $a;
383
        }
384
        $adjmax = ceil($max / $majstep) * $majstep;
385
386
        $adjmin   = floor($min / $majstep) * $majstep;
387
        $adjdiff  = $adjmax - $adjmin;
388
        $numsteps = $adjdiff / $majstep;
389
        while ($numsteps > $maxsteps) {
390
            $majstep  = pow(10, $ld) / $a;
391
            $numsteps = $adjdiff / $majstep;
392
            ++$ld;
393
        }
394
395
        $adjmin  = floor($min / $majstep) * $majstep;
396
        $adjdiff = $adjmax - $adjmin;
0 ignored issues
show
Unused Code introduced by
The assignment to $adjdiff is dead and can be removed.
Loading history...
397
        if ($majend) {
398
            $adjmin  = floor($min / $majstep) * $majstep;
399
            $adjdiff = $adjmax - $adjmin;
400
            $adjmax  = ceil($adjdiff / $majstep) * $majstep + $adjmin;
401
        } else {
402
            $adjmax = ceil($max / $majstep) * $majstep;
403
        }
404
405
        return [$numsteps, $adjmin, $adjmax, $majstep];
406
    }
407
408
    public function IntCalcTicksFreeze($maxsteps, $min, $max, $a)
409
    {
410
        // Same as IntCalcTick but don't change min/max values
411
        $diff = $max - $min;
412
        if ($diff == 0) {
413
            Util\JpGraphError::RaiseL(25075); //('Can\'t automatically determine ticks since min==max.');
414
        } else {
415
            $ld = floor(log10($diff));
416
        }
417
        if ($ld == 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ld does not seem to be defined for all execution paths leading up to this point.
Loading history...
418
            $ld = 1;
419
        }
420
        if ($a == 1) {
421
            $majstep = 1;
422
        } else {
423
            $majstep = pow(10, $ld) / $a;
424
        }
425
426
        $numsteps = floor($diff / $majstep);
427
        while ($numsteps > $maxsteps) {
428
            $majstep  = pow(10, $ld) / $a;
429
            $numsteps = floor($diff / $majstep);
430
            ++$ld;
431
        }
432
433
        return [$numsteps, $majstep];
434
    }
435
436
    public function __get($name)
437
    {
438
        $variable_name = '_' . $name;
439
440
        if (isset($this->{$variable_name})) {
441
            return $this->{$variable_name} * Configs::getConfig('SUPERSAMPLING_SCALE');
442
        }
443
        Util\JpGraphError::RaiseL('25132', $name);
444
    }
445
446
    public function __set($name, $value)
447
    {
448
        $this->{'_' . $name} = $value;
449
    }
450
} // @class
451