Completed
Push — master ( c91059...83bd3e )
by Hannes
11:51
created

AbstractTable::getOpenStandard()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 1
cts 1
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
    public function __construct()
40
    {
41 15
        $this->NumDistances = count($this->Distances);
42
        $this->NumAges = 1 + $this->AgeRange[1] - $this->AgeRange[0];
43 15
    }
44 15
45 15
    /**
46
     * @return array distances with exact age standards [km]
47
     */
48
    public function getAvailableDistances()
49
    {
50 1
        return $this->Distances;
51
    }
52 1
53
    /**
54
     * @return float[] open standard times for all available distances in [s]
55
     */
56
    public function getOpenStandard()
57
    {
58 1
        return $this->OpenStandard;
59
    }
60 1
61
    /**
62
     * @return array [from, to] in [years]
63
     */
64
    public function getAvailableAgeRange()
65
    {
66 1
        return $this->AgeRange;
67
    }
68 1
69
    /**
70
     * @return float [km]
71
     */
72
    public function getMinimalDistance()
73
    {
74
        return $this->Distances[0];
75
    }
76
77 7
    /**
78
     * @param  int       $age           [years]
79 7
     * @param  float     $distance      [km]
80
     * @param  int|float $timeInSeconds [s]
81
     * @return float     age grade in [0.0 .. 1.0]
82
     */
83
    public function getAgePerformance($age, $distance, $timeInSeconds)
84
    {
85
        return $this->getAgeStandard($age, $distance) / $timeInSeconds;
86
    }
87
88 2
    /**
89
     * @param  int       $age           [years]
90 2
     * @param  float     $distance      [km]
91 2
     * @param  int|float $timeInSeconds [s]
92
     * @return AgeGrade
93 2
     */
94 2
    public function getAgeGrade($age, $distance, $timeInSeconds)
95 2
    {
96
        $ageStandard = $this->getAgeStandard($age, $distance);
97 2
        $ageFactor = $this->getAgeFactor($age, $distance);
98
99
        $ageGrade = new AgeGrade($ageStandard / $timeInSeconds);
100
        $ageGrade->setOriginalResult($distance, $timeInSeconds);
101
        $ageGrade->setTableData($ageStandard, $ageFactor);
102
103
        return $ageGrade;
104
    }
105 11
106
    /**
107 11
     * @param  int       $age      [years]
108 11
     * @param  float     $distance [km]
109
     * @return int|float age standard by WMA [s]
110 11
     */
111 10
    public function getAgeStandard($age, $distance)
112
    {
113
        list($distanceIndex, $fraction) = $this->getDistanceIndexWithFraction($distance);
114 3
        $ageFactor = $this->getAgeFactor($age, $distance);
115
116
        if (1.0 === $fraction) {
117
            return $this->OpenStandard[$distanceIndex] / $ageFactor;
118
        }
119
120
        return ((1 - $fraction) * $this->OpenStandard[$distanceIndex - 1] + $fraction * $this->OpenStandard[$distanceIndex]) / $ageFactor;
121
    }
122 11
123
    /**
124 11
     * @param  int   $age      [years]
125 11
     * @param  float $distance [km]
126
     * @return float age grade factor in [0.0 .. 1.0]
127 11
     */
128 6
    protected function getAgeFactor($age, $distance)
129
    {
130
        $ageIndex = $this->getAgeIndex($age);
131 7
        list($distanceIndex, $fraction) = $this->getDistanceIndexWithFraction($distance);
132
133
        if ($distance <= $this->Distances[0] || $distance >= $this->Distances[$this->NumDistances - 1]) {
134
            return $this->AgeFactors[$ageIndex][$distanceIndex];
135
        }
136
137
        return (1 - $fraction) * $this->AgeFactors[$ageIndex][$distanceIndex - 1] + $fraction * $this->AgeFactors[$ageIndex][$distanceIndex];
138 11
    }
139
140 11
    /**
141
     * @param  int $age [years]
142 11
     * @return int age index for internal table
143 1
     */
144 11
    protected function getAgeIndex($age)
145 1
    {
146 1
        list($min, $max) = $this->AgeRange;
147
148 11
        if ($age < $min) {
149
            $age = $min;
150
        } elseif ($age > $max) {
151
            $age = $max;
152
        }
153
154
        return (int) $age - $min;
155
    }
156 11
157
    /**
158 11
     * @param  float $distance [km]
159 4
     * @return array [index, fraction] distance index for internal table
160
     *                        fraction belongs to the returned index, (1 - fraction) to (index - 1)
161
     */
162 11
    protected function getDistanceIndexWithFraction($distance)
163 4
    {
164
        if ($distance <= $this->Distances[0]) {
165
            return [0, 1.0];
166 7
        }
167 7
168 7
        if ($distance >= $this->Distances[$this->NumDistances - 1]) {
169
            return [$this->NumDistances - 1, 1.0];
170 7
        }
171
172 7
        for ($i = 0; $i < $this->NumDistances; ++$i) {
173 7
            if ($this->Distances[$i] >= $distance) {
174
                break;
175 7
            }
176
        }
177
178
        $i = min($i, $this->NumDistances - 1);
179
        $fraction = ($distance - $this->Distances[$i - 1]) / ($this->Distances[$i] - $this->Distances[$i - 1]);
180
181
        return [$i, $fraction];
182
    }
183
}
184