Completed
Pull Request — master (#2)
by Hannes
01:37
created

AbstractTable::getAvailableAgeRange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Runalyze Age Grade.
5
 *
6
 * (c) RUNALYZE <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Runalyze\AgeGrade\Table;
13
14
use Runalyze\AgeGrade\AgeGrade;
15
16
/**
17
 * Classes extending AbstractTable must provide correctly sized $OpenStandard and $AgeFactors.
18
 */
19
abstract class AbstractTable implements TableInterface
20
{
21
    /** @var int */
22
    protected $NumDistances;
23
24
    /** @var int */
25
    protected $NumAges;
26
27
    /** @var float[] available distances [km] */
28
    protected $Distances = [];
29
30
    /** @var int[] available ages [from, to] in [years] */
31
    protected $AgeRange = [5, 100];
32
33
    /** @var float[] open standard times for all available distances in [s] */
34
    protected $OpenStandard = [];
35
36
    /** @var float[] for each age an array with factors for all available distances in [0.0 .. 1.0] */
37
    protected $AgeFactors = [];
38
39 21
    public function __construct()
40
    {
41 21
        $this->NumDistances = count($this->Distances);
42 21
        $this->NumAges = 1 + $this->AgeRange[1] - $this->AgeRange[0];
43 21
    }
44
45
    /**
46
     * @return array distances with exact age standards [km]
47
     */
48 3
    public function getAvailableDistances()
49
    {
50 3
        return $this->Distances;
51
    }
52
53
    /**
54
     * @return float[] open standard times for all available distances in [s]
55
     */
56 3
    public function getOpenStandard()
57
    {
58 3
        return $this->OpenStandard;
59
    }
60
61
    /**
62
     * @return array [from, to] in [years]
63
     */
64 1
    public function getAvailableAgeRange()
65
    {
66 1
        return $this->AgeRange;
67
    }
68
69
    /**
70
     * @return float [km]
71
     */
72 2
    public function getMinimalDistance()
73
    {
74 2
        return $this->Distances[0];
75
    }
76
77
    /**
78
     * @param  int       $age           [years]
79
     * @param  float     $distance      [km]
80
     * @param  int|float $timeInSeconds [s]
81
     * @return float     age grade in [0.0 .. 1.0]
82
     */
83 7
    public function getAgePerformance($age, $distance, $timeInSeconds)
84
    {
85 7
        return $this->getAgeStandard($age, $distance) / $timeInSeconds;
86
    }
87
88
    /**
89
     * @param  int       $age           [years]
90
     * @param  float     $distance      [km]
91
     * @param  int|float $timeInSeconds [s]
92
     * @return AgeGrade
93
     */
94 2
    public function getAgeGrade($age, $distance, $timeInSeconds)
95
    {
96 2
        $ageStandard = $this->getAgeStandard($age, $distance);
97 2
        $ageFactor = $this->getAgeFactor($age, $distance);
98
99 2
        $ageGrade = new AgeGrade($ageStandard / $timeInSeconds);
100 2
        $ageGrade->setOriginalResult($distance, $timeInSeconds);
101 2
        $ageGrade->setTableData($ageStandard, $ageFactor);
102
103 2
        return $ageGrade;
104
    }
105
106
    /**
107
     * @param  int       $age      [years]
108
     * @param  float     $distance [km]
109
     * @return int|float age standard by WMA [s]
110
     */
111 13
    public function getAgeStandard($age, $distance)
112
    {
113 13
        list($distanceIndex, $fraction) = $this->getDistanceIndexWithFraction($distance);
114 13
        $ageFactor = $this->getAgeFactor($age, $distance);
115
116 13
        if (1.0 === $fraction) {
117 12
            return $this->OpenStandard[$distanceIndex] / $ageFactor;
118
        }
119
120 3
        return ((1 - $fraction) * $this->OpenStandard[$distanceIndex - 1] + $fraction * $this->OpenStandard[$distanceIndex]) / $ageFactor;
121
    }
122
123
    /**
124
     * @param  int   $age      [years]
125
     * @param  float $distance [km]
126
     * @return float age grade factor in [0.0 .. 1.0]
127
     */
128 13
    protected function getAgeFactor($age, $distance)
129
    {
130 13
        $ageIndex = $this->getAgeIndex($age);
131 13
        list($distanceIndex, $fraction) = $this->getDistanceIndexWithFraction($distance);
132
133 13
        if ($distance <= $this->Distances[0] || $distance >= $this->Distances[$this->NumDistances - 1]) {
134 6
            return $this->AgeFactors[$ageIndex][$distanceIndex];
135
        }
136
137 9
        return (1 - $fraction) * $this->AgeFactors[$ageIndex][$distanceIndex - 1] + $fraction * $this->AgeFactors[$ageIndex][$distanceIndex];
138
    }
139
140
    /**
141
     * @param  int $age [years]
142
     * @return int age index for internal table
143
     */
144 13
    protected function getAgeIndex($age)
145
    {
146 13
        list($min, $max) = $this->AgeRange;
147
148 13
        if ($age < $min) {
149 1
            $age = $min;
150 13
        } elseif ($age > $max) {
151 1
            $age = $max;
152 1
        }
153
154 13
        return (int) $age - $min;
155
    }
156
157
    /**
158
     * @param  float $distance [km]
159
     * @return array [index, fraction] distance index for internal table
160
     *                        fraction belongs to the returned index, (1 - fraction) to (index - 1)
161
     */
162 13
    protected function getDistanceIndexWithFraction($distance)
163
    {
164 13
        if ($distance <= $this->Distances[0]) {
165 4
            return [0, 1.0];
166
        }
167
168 13
        if ($distance >= $this->Distances[$this->NumDistances - 1]) {
169 6
            return [$this->NumDistances - 1, 1.0];
170
        }
171
172 9
        for ($i = 0; $i < $this->NumDistances; ++$i) {
173 9
            if ($this->Distances[$i] >= $distance) {
174 9
                break;
175
            }
176 9
        }
177
178 9
        $i = min($i, $this->NumDistances - 1);
179 9
        $fraction = ($distance - $this->Distances[$i - 1]) / ($this->Distances[$i] - $this->Distances[$i - 1]);
180
181 9
        return [$i, $fraction];
182
    }
183
}
184