Passed
Push — 4.x ( 1d49e7...4cde9a )
by Doug
06:44
created

Point::reversiblePolynomialUnitless()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 36
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 17
c 0
b 0
f 0
dl 0
loc 36
ccs 18
cts 18
cp 1
rs 9.3888
cc 5
nc 9
nop 8
crap 5

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord;
10
11
use DateTimeImmutable;
12
use PHPCoord\CoordinateOperation\CoordinateOperationMethods;
13
use PHPCoord\CoordinateOperation\CoordinateOperationParams;
0 ignored issues
show
Bug introduced by
The type PHPCoord\CoordinateOpera...ordinateOperationParams was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use PHPCoord\CoordinateOperation\CoordinateOperations;
0 ignored issues
show
Bug introduced by
The type PHPCoord\CoordinateOperation\CoordinateOperations was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use PHPCoord\CoordinateReferenceSystem\CoordinateReferenceSystem;
16
use PHPCoord\CoordinateSystem\Axis;
17
use PHPCoord\UnitOfMeasure\Angle\Angle;
18
use PHPCoord\UnitOfMeasure\Length\Length;
19
use PHPCoord\UnitOfMeasure\Scale\Coefficient;
20
use PHPCoord\UnitOfMeasure\Scale\Scale;
21
use PHPCoord\UnitOfMeasure\UnitOfMeasure;
22
use PHPCoord\UnitOfMeasure\UnitOfMeasureFactory;
23
use Stringable;
24
25
abstract class Point implements Stringable
26
{
27
    protected const NEWTON_RAPHSON_CONVERGENCE = 1e-15;
28
29
    /**
30
     * @internal
31
     */
32 8
    public function performOperation(string $srid, CoordinateReferenceSystem $to, bool $inReverse): self
33
    {
34 8
        $operations = [];
35 8
        $operation = CoordinateOperations::getOperationData($srid);
36 8
        if (isset($operation['operations'])) {
37
            foreach ($operation['operations'] as $subOperation) {
38
                $subOperationData = CoordinateOperations::getOperationData($subOperation['operation']);
39
                $subOperationData['source_crs'] = $subOperation['source_crs'];
40
                $subOperationData['target_crs'] = $subOperation['target_crs'];
41
                $operations[$subOperation['operation']] = $subOperationData;
42
            }
43
        } else {
44 8
            $operations[$srid] = $operation;
45
        }
46
47 8
        if ($inReverse) {
48 1
            $operations = array_reverse($operations, true);
49
        }
50
51 8
        $point = $this;
52 8
        foreach ($operations as $operationSrid => $operation) {
53 8
            $method = CoordinateOperationMethods::getFunctionName($operation['method']);
54 8
            if (isset($operation['source_crs']) && $operation['target_crs']) {
55
                $destCRS = CoordinateReferenceSystem::fromSRID($inReverse ? $operation['source_crs'] : $operation['target_crs']);
56
            } else {
57 8
                $destCRS = $to;
58
            }
59
60 8
            $params = [];
61 8
            $powerCoefficients = [];
62 8
            foreach (CoordinateOperationParams::getParamData($operationSrid) as $paramName => $paramData) {
63 8
                $value = $paramData['value'];
64 8
                if ($inReverse && $paramData['reverses']) {
65
                    $value *= -1;
66
                }
67 8
                if ($paramData['uom']) {
68 8
                    $param = UnitOfMeasureFactory::makeUnit($value, $paramData['uom']);
69
                } else {
70
                    $param = $paramData['value'];
71
                }
72 8
                $paramName = static::camelCase($paramName);
73 8
                if (strpos($paramName, 'Au') === 0 || strpos($paramName, 'Bu') === 0) {
74
                    $powerCoefficients[$paramName] = $param;
75
                } else {
76 8
                    $params[$paramName] = $param;
77
                }
78
            }
79 8
            if ($powerCoefficients) {
80
                $params['powerCoefficients'] = $powerCoefficients;
81
            }
82 8
            if (in_array($operation['method'], [
83 8
                CoordinateOperationMethods::EPSG_SIMILARITY_TRANSFORMATION,
84
                CoordinateOperationMethods::EPSG_AFFINE_PARAMETRIC_TRANSFORMATION,
85 8
            ], true)) {
86
                $params['inReverse'] = $inReverse;
87
            }
88
89 8
            if (PHP_MAJOR_VERSION >= 8) {
90
                $point = $point->$method($destCRS, ...$params);
91
            } else {
92 8
                $point = $point->$method($destCRS, ...array_values($params));
93
            }
94
        }
95
96 8
        $point->crs = $to; //some operations are reused across CRSses (e.g. ETRS89 and WGS84), so the $destCRS of the final suboperation might not be the intended target
97
98 8
        return $point;
99
    }
100
101 8
    protected static function camelCase(string $string): string
102
    {
103 8
        $string = str_replace([' ', '-'], '', ucwords($string, ' -'));
104 8
        if (!preg_match('/[ABC][uv\d]/', $string)) {
105 8
            $string = lcfirst($string);
106
        }
107
108 8
        return $string;
109
    }
110
111 195
    protected function getAxisByName(string $name): ?Axis
112
    {
113 195
        foreach ($this->getCRS()->getCoordinateSystem()->getAxes() as $axis) {
114 195
            if ($axis->getName() === $name) {
115 195
                return $axis;
116
            }
117
        }
118
119 135
        return null;
120
    }
121
122 10
    protected static function sign(float $number): int
123
    {
124 10
        if ($number < 0) {
125
            return -1;
126
        }
127
128 10
        return 1;
129
    }
130
131
    /**
132
     * General polynomial.
133
     * @param Coefficient[] $powerCoefficients
134
     */
135 1
    protected function generalPolynomialUnitless(
136
        float $xs,
137
        float $ys,
138
        UnitOfMeasure $ordinate1OfEvaluationPointInSourceCRS,
139
        UnitOfMeasure $ordinate2OfEvaluationPointInSourceCRS,
140
        UnitOfMeasure $ordinate1OfEvaluationPointInTargetCRS,
141
        UnitOfMeasure $ordinate2OfEvaluationPointInTargetCRS,
142
        Scale $scalingFactorForSourceCRSCoordDifferences,
143
        Scale $scalingFactorForTargetCRSCoordDifferences,
144
        Scale $A0,
145
        Scale $B0,
146
        array $powerCoefficients
147
    ): array {
148 1
        $xso = $ordinate1OfEvaluationPointInSourceCRS->getValue();
149 1
        $yso = $ordinate2OfEvaluationPointInSourceCRS->getValue();
150 1
        $xto = $ordinate1OfEvaluationPointInTargetCRS->getValue();
151 1
        $yto = $ordinate2OfEvaluationPointInTargetCRS->getValue();
152
153 1
        $U = $scalingFactorForSourceCRSCoordDifferences->asUnity()->getValue() * ($xs - $xso);
154 1
        $V = $scalingFactorForSourceCRSCoordDifferences->asUnity()->getValue() * ($ys - $yso);
155
156 1
        $mTdX = $A0->getValue();
157 1
        foreach ($powerCoefficients as $coefficientName => $coefficientValue) {
158 1
            if ($coefficientName[0] === 'A') {
159 1
                sscanf($coefficientName, 'Au%dv%d', $uPower, $vPower);
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $vPower seems to be never defined.
Loading history...
160 1
                $mTdX += $coefficientValue->getValue() * $U ** $uPower * $V ** $vPower;
161
            }
162
        }
163
164 1
        $mTdY = $B0->getValue();
165 1
        foreach ($powerCoefficients as $coefficientName => $coefficientValue) {
166 1
            if ($coefficientName[0] === 'B') {
167 1
                sscanf($coefficientName, 'Bu%dv%d', $uPower, $vPower);
168 1
                $mTdY += $coefficientValue->getValue() * $U ** $uPower * $V ** $vPower;
169
            }
170
        }
171
172 1
        $xt = $xs - $xso + $xto + $mTdX / $scalingFactorForTargetCRSCoordDifferences->asUnity()->getValue();
173 1
        $yt = $ys - $yso + $yto + $mTdY / $scalingFactorForTargetCRSCoordDifferences->asUnity()->getValue();
174
175 1
        return ['xt' => $xt, 'yt' => $yt];
176
    }
177
178
    /**
179
     * Reversible polynomial.
180
     */
181 2
    protected function reversiblePolynomialUnitless(
182
        float $xs,
183
        float $ys,
184
        Angle $ordinate1OfEvaluationPoint,
185
        Angle $ordinate2OfEvaluationPoint,
186
        Scale $scalingFactorForCoordDifferences,
187
        Scale $A0,
188
        Scale $B0,
189
        array $powerCoefficients
190
    ): array {
191 2
        $xo = $ordinate1OfEvaluationPoint->getValue();
192 2
        $yo = $ordinate2OfEvaluationPoint->getValue();
193
194 2
        $U = $scalingFactorForCoordDifferences->asUnity()->getValue() * ($xs - $xo);
195 2
        $V = $scalingFactorForCoordDifferences->asUnity()->getValue() * ($ys - $yo);
196
197 2
        $mTdX = $A0->getValue();
198 2
        foreach ($powerCoefficients as $coefficientName => $coefficientValue) {
199 2
            if ($coefficientName[0] === 'A') {
200 2
                sscanf($coefficientName, 'Au%dv%d', $uPower, $vPower);
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $vPower seems to be never defined.
Loading history...
201 2
                $mTdX += $coefficientValue->getValue() * $U ** $uPower * $V ** $vPower;
202
            }
203
        }
204
205 2
        $mTdY = $B0->getValue();
206 2
        foreach ($powerCoefficients as $coefficientName => $coefficientValue) {
207 2
            if ($coefficientName[0] === 'B') {
208 2
                sscanf($coefficientName, 'Bu%dv%d', $uPower, $vPower);
209 2
                $mTdY += $coefficientValue->getValue() * $U ** $uPower * $V ** $vPower;
210
            }
211
        }
212
213 2
        $xt = $xs + $mTdX * $scalingFactorForCoordDifferences->asUnity()->getValue();
214 2
        $yt = $ys + $mTdY * $scalingFactorForCoordDifferences->asUnity()->getValue();
215
216 2
        return ['xt' => $xt, 'yt' => $yt];
217
    }
218
219
    /**
220
     * Floating point vagaries mean that it's possible for inputs to be e.g. 1.00000000000001 which makes PHP give a
221
     * silent NaN as output so inputs need to be capped. atan/atan2 are not affected, they seem to cap internally.
222
     */
223 1
    protected static function acos(float $num): float
224
    {
225 1
        if ($num > 1.0) {
226
            $num = 1.0;
227 1
        } elseif ($num < -1) {
228
            $num = -1.0;
229
        }
230
231 1
        return acos($num);
232
    }
233
234
    /**
235
     * Floating point vagaries mean that it's possible for inputs to be e.g. 1.00000000000001 which makes PHP give a
236
     * silent NaN as output so inputs need to be capped. atan/atan2 are not affected, they seem to cap internally.
237
     */
238 39
    protected static function asin(float $num): float
239
    {
240 39
        if ($num > 1.0) {
241
            $num = 1.0;
242 39
        } elseif ($num < -1.0) {
243
            $num = -1.0;
244
        }
245
246 39
        return asin($num);
247
    }
248
249
    abstract public function getCRS(): CoordinateReferenceSystem;
250
251
    abstract public function getCoordinateEpoch(): ?DateTimeImmutable;
252
253
    abstract public function calculateDistance(self $to): Length;
254
}
255