coordinateFrameMolodenskyBadekas()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 17
c 0
b 0
f 0
nc 1
nop 11
dl 0
loc 32
ccs 17
cts 17
cp 1
crap 1
rs 9.7

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
/**
4
 * PHPCoord.
5
 *
6
 * @author Doug Wright
7
 */
8
declare(strict_types=1);
9
10
namespace PHPCoord\Point;
11
12
use DateTime;
13
use DateTimeImmutable;
14
use DateTimeInterface;
15
use PHPCoord\CoordinateOperation\AutoConversion;
16
use PHPCoord\CoordinateOperation\ConvertiblePoint;
17
use PHPCoord\CoordinateOperation\GeocentricValue;
18
use PHPCoord\CoordinateOperation\GeographicValue;
19
use PHPCoord\CoordinateReferenceSystem\Geocentric;
20
use PHPCoord\CoordinateReferenceSystem\Geographic;
21
use PHPCoord\CoordinateReferenceSystem\Geographic2D;
22
use PHPCoord\CoordinateReferenceSystem\Geographic3D;
23
use PHPCoord\CoordinateSystem\Axis;
24
use PHPCoord\Exception\InvalidCoordinateException;
25
use PHPCoord\Exception\InvalidCoordinateReferenceSystemException;
26
use PHPCoord\Geometry\Geodesic;
27
use PHPCoord\UnitOfMeasure\Angle\Angle;
28
use PHPCoord\UnitOfMeasure\Angle\Radian;
29
use PHPCoord\UnitOfMeasure\Length\Length;
30
use PHPCoord\UnitOfMeasure\Length\Metre;
31
use PHPCoord\UnitOfMeasure\Rate;
32
use PHPCoord\UnitOfMeasure\Scale\Scale;
33
use PHPCoord\UnitOfMeasure\Scale\Unity;
34
use PHPCoord\UnitOfMeasure\Time\Time;
35
use PHPCoord\UnitOfMeasure\Time\Year;
36
37
use function abs;
38
use function sprintf;
39
40
/**
41
 * Coordinate representing a point in ECEF geocentric form.
42
 */
43
class GeocentricPoint extends Point implements ConvertiblePoint
44
{
45
    use AutoConversion;
46
47
    /**
48
     * X co-ordinate.
49
     */
50
    protected Length $x;
51
52
    /**
53
     * Y co-ordinate.
54
     */
55
    protected Length $y;
56
57
    /**
58
     * Z co-ordinate.
59
     */
60
    protected Length $z;
61
62
    /**
63
     * Coordinate reference system.
64
     */
65
    protected Geocentric $crs;
66
67
    /**
68
     * Coordinate epoch (date for which the specified coordinates represented this point).
69
     */
70
    protected ?DateTimeImmutable $epoch;
71 381
72
    protected function __construct(Geocentric $crs, Length $x, Length $y, Length $z, ?DateTimeInterface $epoch = null)
73 381
    {
74 381
        $this->crs = $crs;
75 381
        $this->x = $x::convert($x, $this->crs->getCoordinateSystem()->getAxisByName(Axis::GEOCENTRIC_X)->getUnitOfMeasureId());
76 381
        $this->y = $y::convert($y, $this->crs->getCoordinateSystem()->getAxisByName(Axis::GEOCENTRIC_Y)->getUnitOfMeasureId());
77
        $this->z = $z::convert($z, $this->crs->getCoordinateSystem()->getAxisByName(Axis::GEOCENTRIC_Z)->getUnitOfMeasureId());
78 381
79 54
        if ($epoch instanceof DateTime) {
80
            $epoch = DateTimeImmutable::createFromMutable($epoch);
81 381
        }
82
        $this->epoch = $epoch;
83
    }
84
85
    /**
86
     * @param Length $x refer to CRS for preferred unit of measure, but any length unit accepted
87
     * @param Length $y refer to CRS for preferred unit of measure, but any length unit accepted
88
     * @param Length $z refer to CRS for preferred unit of measure, but any length unit accepted
89 381
     */
90
    public static function create(Geocentric $crs, Length $x, Length $y, Length $z, ?DateTimeInterface $epoch = null): self
91 381
    {
92
        return new self($crs, $x, $y, $z, $epoch);
93
    }
94 171
95
    public function getX(): Length
96 171
    {
97
        return $this->x;
98
    }
99 171
100
    public function getY(): Length
101 171
    {
102
        return $this->y;
103
    }
104 171
105
    public function getZ(): Length
106 171
    {
107
        return $this->z;
108
    }
109 63
110
    public function getCRS(): Geocentric
111 63
    {
112
        return $this->crs;
113
    }
114 54
115
    public function getCoordinateEpoch(): ?DateTimeImmutable
116 54
    {
117
        return $this->epoch;
118
    }
119
120
    /**
121
     * Calculate surface distance between two points.
122 18
     */
123
    public function calculateDistance(Point $to): Length
124
    {
125 18
        try {
126 18
            if ($to instanceof ConvertiblePoint) {
127
                $to = $to->convert($this->crs);
128
            }
129 18
        } finally {
130 9
            if ($to->getCRS()->getSRID() !== $this->crs->getSRID()) {
131
                throw new InvalidCoordinateReferenceSystemException('Can only calculate distances between two points in the same CRS');
132
            }
133
134 9
            /** @var GeographicPoint $to */
135
            $geodesic = new Geodesic($this->getCRS()->getDatum()->getEllipsoid());
136 9
137
            return $geodesic->distance($this->asGeographicValue(), $to->asGeographicValue());
138
        }
139
    }
140 27
141
    public function __toString(): string
142 27
    {
143
        return "({$this->x}, {$this->y}, {$this->z})";
144
    }
145
146
    /**
147
     * Geographic/geocentric conversions
148
     * In applications it is often concatenated with the 3- 7- or 10-parameter transformations 9603, 9606, 9607 or
149
     * 9636 to form a geographic to geographic transformation.
150 165
     */
151
    public function geographicGeocentric(
152
        Geographic2D|Geographic3D $to
153 165
    ): GeographicPoint {
154 165
        $geocentricValue = new GeocentricValue($this->x, $this->y, $this->z, $to->getDatum());
155
        $asGeographic = $geocentricValue->asGeographicValue();
156 165
157
        return GeographicPoint::create($to, $asGeographic->getLatitude(), $asGeographic->getLongitude(), $to instanceof Geographic3D ? $asGeographic->getHeight() : null, $this->epoch);
158
    }
159
160
    /**
161
     * Coordinate Frame rotation (geocentric domain)
162
     * This method is a specific case of the Molodensky-Badekas (CF) method (code 1034) in which the evaluation point
163
     * is at the geocentre with coordinate values of zero. Note the analogy with the Position Vector method (code 1033)
164
     * but beware of the differences!
165 183
     */
166
    public function coordinateFrameRotation(
167
        Geocentric $to,
168
        Length $xAxisTranslation,
169
        Length $yAxisTranslation,
170
        Length $zAxisTranslation,
171
        Angle $xAxisRotation,
172
        Angle $yAxisRotation,
173
        Angle $zAxisRotation,
174
        Scale $scaleDifference
175 183
    ): self {
176 183
        return $this->coordinateFrameMolodenskyBadekas(
177 183
            $to,
178 183
            $xAxisTranslation,
179 183
            $yAxisTranslation,
180 183
            $zAxisTranslation,
181 183
            $xAxisRotation,
182 183
            $yAxisRotation,
183 183
            $zAxisRotation,
184 183
            $scaleDifference,
185 183
            new Metre(0),
186 183
            new Metre(0),
187 183
            new Metre(0)
188
        );
189
    }
190
191
    /**
192
     * Molodensky-Badekas (CF geocentric domain)
193
     * See method codes 1039 and 9636 for this operation in other coordinate domains and method code 1061 for opposite
194
     * rotation convention in geocentric domain.
195 192
     */
196
    public function coordinateFrameMolodenskyBadekas(
197
        Geocentric $to,
198
        Length $xAxisTranslation,
199
        Length $yAxisTranslation,
200
        Length $zAxisTranslation,
201
        Angle $xAxisRotation,
202
        Angle $yAxisRotation,
203
        Angle $zAxisRotation,
204
        Scale $scaleDifference,
205
        Length $ordinate1OfEvaluationPoint,
206
        Length $ordinate2OfEvaluationPoint,
207
        Length $ordinate3OfEvaluationPoint
208 192
    ): self {
209 192
        $xs = $this->x->asMetres()->getValue();
210 192
        $ys = $this->y->asMetres()->getValue();
211 192
        $zs = $this->z->asMetres()->getValue();
212 192
        $tx = $xAxisTranslation->asMetres()->getValue();
213 192
        $ty = $yAxisTranslation->asMetres()->getValue();
214 192
        $tz = $zAxisTranslation->asMetres()->getValue();
215 192
        $rx = $xAxisRotation->asRadians()->getValue();
216 192
        $ry = $yAxisRotation->asRadians()->getValue();
217 192
        $rz = $zAxisRotation->asRadians()->getValue();
218 192
        $M = 1 + $scaleDifference->asUnity()->getValue();
219 192
        $xp = $ordinate1OfEvaluationPoint->asMetres()->getValue();
220 192
        $yp = $ordinate2OfEvaluationPoint->asMetres()->getValue();
221
        $zp = $ordinate3OfEvaluationPoint->asMetres()->getValue();
222 192
223 192
        $xt = $M * ((($xs - $xp) * 1) + (($ys - $yp) * $rz) + (($zs - $zp) * -$ry)) + $tx + $xp;
224 192
        $yt = $M * ((($xs - $xp) * -$rz) + (($ys - $yp) * 1) + (($zs - $zp) * $rx)) + $ty + $yp;
225
        $zt = $M * ((($xs - $xp) * $ry) + (($ys - $yp) * -$rx) + (($zs - $zp) * 1)) + $tz + $zp;
226 192
227
        return static::create($to, new Metre($xt), new Metre($yt), new Metre($zt), $this->epoch);
228
    }
229
230
    /**
231
     * Position Vector transformation (geocentric domain)
232
     * This method is a specific case of the Molodensky-Badekas (PV) method (code 1061) in which the evaluation point
233
     * is the geocentre with coordinate values of zero. Note the analogy with the Coordinate Frame method (code 1032)
234
     * but beware of the differences!
235 171
     */
236
    public function positionVectorTransformation(
237
        Geocentric $to,
238
        Length $xAxisTranslation,
239
        Length $yAxisTranslation,
240
        Length $zAxisTranslation,
241
        Angle $xAxisRotation,
242
        Angle $yAxisRotation,
243
        Angle $zAxisRotation,
244
        Scale $scaleDifference
245 171
    ): self {
246 171
        return $this->positionVectorMolodenskyBadekas(
247 171
            $to,
248 171
            $xAxisTranslation,
249 171
            $yAxisTranslation,
250 171
            $zAxisTranslation,
251 171
            $xAxisRotation,
252 171
            $yAxisRotation,
253 171
            $zAxisRotation,
254 171
            $scaleDifference,
255 171
            new Metre(0),
256 171
            new Metre(0),
257 171
            new Metre(0)
258
        );
259
    }
260
261
    /**
262
     * Molodensky-Badekas (PV geocentric domain)
263
     * See method codes 1062 and 1063 for this operation in other coordinate domains and method code 1034 for opposite
264
     * rotation convention in geocentric domain.
265 180
     */
266
    public function positionVectorMolodenskyBadekas(
267
        Geocentric $to,
268
        Length $xAxisTranslation,
269
        Length $yAxisTranslation,
270
        Length $zAxisTranslation,
271
        Angle $xAxisRotation,
272
        Angle $yAxisRotation,
273
        Angle $zAxisRotation,
274
        Scale $scaleDifference,
275
        Length $ordinate1OfEvaluationPoint,
276
        Length $ordinate2OfEvaluationPoint,
277
        Length $ordinate3OfEvaluationPoint
278 180
    ): self {
279 180
        $xs = $this->x->asMetres()->getValue();
280 180
        $ys = $this->y->asMetres()->getValue();
281 180
        $zs = $this->z->asMetres()->getValue();
282 180
        $tx = $xAxisTranslation->asMetres()->getValue();
283 180
        $ty = $yAxisTranslation->asMetres()->getValue();
284 180
        $tz = $zAxisTranslation->asMetres()->getValue();
285 180
        $rx = $xAxisRotation->asRadians()->getValue();
286 180
        $ry = $yAxisRotation->asRadians()->getValue();
287 180
        $rz = $zAxisRotation->asRadians()->getValue();
288 180
        $M = 1 + $scaleDifference->asUnity()->getValue();
289 180
        $xp = $ordinate1OfEvaluationPoint->asMetres()->getValue();
290 180
        $yp = $ordinate2OfEvaluationPoint->asMetres()->getValue();
291
        $zp = $ordinate3OfEvaluationPoint->asMetres()->getValue();
292 180
293 180
        $xt = $M * ((($xs - $xp) * 1) + (($ys - $yp) * -$rz) + (($zs - $zp) * $ry)) + $tx + $xp;
294 180
        $yt = $M * ((($xs - $xp) * $rz) + (($ys - $yp) * 1) + (($zs - $zp) * -$rx)) + $ty + $yp;
295
        $zt = $M * ((($xs - $xp) * -$ry) + (($ys - $yp) * $rx) + (($zs - $zp) * 1)) + $tz + $zp;
296 180
297
        return static::create($to, new Metre($xt), new Metre($yt), new Metre($zt), $this->epoch);
298
    }
299
300
    /**
301
     * Geocentric translations
302
     * This method allows calculation of geocentric coords in the target system by adding the parameter values to the
303
     * corresponding coordinates of the point in the source system. See methods 1035 and 9603 for similar tfms
304
     * operating between other CRSs types.
305 9
     */
306
    public function geocentricTranslation(
307
        Geocentric $to,
308
        Length $xAxisTranslation,
309
        Length $yAxisTranslation,
310
        Length $zAxisTranslation
311 9
    ): self {
312 9
        return $this->positionVectorTransformation(
313 9
            $to,
314 9
            $xAxisTranslation,
315 9
            $yAxisTranslation,
316 9
            $zAxisTranslation,
317 9
            new Radian(0),
318 9
            new Radian(0),
319 9
            new Radian(0),
320 9
            new Unity(0)
321
        );
322
    }
323
324
    /**
325
     * Time-dependent Coordinate Frame rotation (geocen)
326
     * Note the analogy with the Time-dependent Position Vector transformation (code 1053) but beware of the
327
     * differences!  The Position Vector convention is used by IAG. See method codes 1057 and 1058 for similar methods
328
     * operating between other CRS types.
329 30
     */
330
    public function timeDependentCoordinateFrameRotation(
331
        Geocentric $to,
332
        Length $xAxisTranslation,
333
        Length $yAxisTranslation,
334
        Length $zAxisTranslation,
335
        Angle $xAxisRotation,
336
        Angle $yAxisRotation,
337
        Angle $zAxisRotation,
338
        Scale $scaleDifference,
339
        Rate $rateOfChangeOfXAxisTranslation,
340
        Rate $rateOfChangeOfYAxisTranslation,
341
        Rate $rateOfChangeOfZAxisTranslation,
342
        Rate $rateOfChangeOfXAxisRotation,
343
        Rate $rateOfChangeOfYAxisRotation,
344
        Rate $rateOfChangeOfZAxisRotation,
345
        Rate $rateOfChangeOfScaleDifference,
346
        Time $parameterReferenceEpoch
347
    ): self {
348 30
        // Points use PHP DateTimes for ease of use, but transformations use decimal years...
349 30
        $pointEpoch = Year::fromDateTime($this->epoch ?? new DateTime());
350 30
        $yearsToAdjust = $pointEpoch->subtract($parameterReferenceEpoch)->getValue();
351 30
        $xAxisTranslation = $xAxisTranslation->add($rateOfChangeOfXAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfXAxisTran...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Angle\Angle and PHPCoord\UnitOfMeasure\Scale\Scale; however, parameter $unit of PHPCoord\UnitOfMeasure\Length\Length::add() does only seem to accept PHPCoord\UnitOfMeasure\Length\Length, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

351
        $xAxisTranslation = $xAxisTranslation->add(/** @scrutinizer ignore-type */ $rateOfChangeOfXAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
352 30
        $yAxisTranslation = $yAxisTranslation->add($rateOfChangeOfYAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
353 30
        $zAxisTranslation = $zAxisTranslation->add($rateOfChangeOfZAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
354 30
        $xAxisRotation = $xAxisRotation->add($rateOfChangeOfXAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfXAxisRota...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Length\Length and PHPCoord\UnitOfMeasure\Scale\Scale; however, parameter $unit of PHPCoord\UnitOfMeasure\Angle\Angle::add() does only seem to accept PHPCoord\UnitOfMeasure\Angle\Angle, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

354
        $xAxisRotation = $xAxisRotation->add(/** @scrutinizer ignore-type */ $rateOfChangeOfXAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
355 30
        $yAxisRotation = $yAxisRotation->add($rateOfChangeOfYAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
356 30
        $zAxisRotation = $zAxisRotation->add($rateOfChangeOfZAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
357
        $scaleDifference = $scaleDifference->add($rateOfChangeOfScaleDifference->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfScaleDiff...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Angle\Angle and PHPCoord\UnitOfMeasure\Length\Length; however, parameter $unit of PHPCoord\UnitOfMeasure\Scale\Scale::add() does only seem to accept PHPCoord\UnitOfMeasure\Scale\Scale, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

357
        $scaleDifference = $scaleDifference->add(/** @scrutinizer ignore-type */ $rateOfChangeOfScaleDifference->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
358 30
359
        return $this->coordinateFrameRotation($to, $xAxisTranslation, $yAxisTranslation, $zAxisTranslation, $xAxisRotation, $yAxisRotation, $zAxisRotation, $scaleDifference);
360
    }
361
362
    /**
363
     * Time-dependent Position Vector tfm (geocentric)
364
     * Note the analogy with the Time-dependent Coordinate Frame rotation (code 1056) but beware of the differences!
365
     * The Position Vector convention is used by IAG. See method codes 1054 and 1055 for similar methods operating
366
     * between other CRS types.
367 126
     */
368
    public function timeDependentPositionVectorTransformation(
369
        Geocentric $to,
370
        Length $xAxisTranslation,
371
        Length $yAxisTranslation,
372
        Length $zAxisTranslation,
373
        Angle $xAxisRotation,
374
        Angle $yAxisRotation,
375
        Angle $zAxisRotation,
376
        Scale $scaleDifference,
377
        Rate $rateOfChangeOfXAxisTranslation,
378
        Rate $rateOfChangeOfYAxisTranslation,
379
        Rate $rateOfChangeOfZAxisTranslation,
380
        Rate $rateOfChangeOfXAxisRotation,
381
        Rate $rateOfChangeOfYAxisRotation,
382
        Rate $rateOfChangeOfZAxisRotation,
383
        Rate $rateOfChangeOfScaleDifference,
384
        Time $parameterReferenceEpoch
385
    ): self {
386 126
        // Points use PHP DateTimes for ease of use, but transformations use decimal years...
387 126
        $pointEpoch = Year::fromDateTime($this->epoch ?? new DateTime());
388 126
        $yearsToAdjust = $pointEpoch->subtract($parameterReferenceEpoch)->getValue();
389 126
        $xAxisTranslation = $xAxisTranslation->add($rateOfChangeOfXAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfXAxisTran...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Angle\Angle and PHPCoord\UnitOfMeasure\Scale\Scale; however, parameter $unit of PHPCoord\UnitOfMeasure\Length\Length::add() does only seem to accept PHPCoord\UnitOfMeasure\Length\Length, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

389
        $xAxisTranslation = $xAxisTranslation->add(/** @scrutinizer ignore-type */ $rateOfChangeOfXAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
390 126
        $yAxisTranslation = $yAxisTranslation->add($rateOfChangeOfYAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
391 126
        $zAxisTranslation = $zAxisTranslation->add($rateOfChangeOfZAxisTranslation->getChangePerYear()->multiply($yearsToAdjust));
392 126
        $xAxisRotation = $xAxisRotation->add($rateOfChangeOfXAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfXAxisRota...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Length\Length and PHPCoord\UnitOfMeasure\Scale\Scale; however, parameter $unit of PHPCoord\UnitOfMeasure\Angle\Angle::add() does only seem to accept PHPCoord\UnitOfMeasure\Angle\Angle, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

392
        $xAxisRotation = $xAxisRotation->add(/** @scrutinizer ignore-type */ $rateOfChangeOfXAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
393 126
        $yAxisRotation = $yAxisRotation->add($rateOfChangeOfYAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
394 126
        $zAxisRotation = $zAxisRotation->add($rateOfChangeOfZAxisRotation->getChangePerYear()->multiply($yearsToAdjust));
395
        $scaleDifference = $scaleDifference->add($rateOfChangeOfScaleDifference->getChangePerYear()->multiply($yearsToAdjust));
0 ignored issues
show
Bug introduced by
It seems like $rateOfChangeOfScaleDiff...ultiply($yearsToAdjust) can also be of type PHPCoord\UnitOfMeasure\Angle\Angle and PHPCoord\UnitOfMeasure\Length\Length; however, parameter $unit of PHPCoord\UnitOfMeasure\Scale\Scale::add() does only seem to accept PHPCoord\UnitOfMeasure\Scale\Scale, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

395
        $scaleDifference = $scaleDifference->add(/** @scrutinizer ignore-type */ $rateOfChangeOfScaleDifference->getChangePerYear()->multiply($yearsToAdjust));
Loading history...
396 126
397
        return $this->positionVectorTransformation($to, $xAxisTranslation, $yAxisTranslation, $zAxisTranslation, $xAxisRotation, $yAxisRotation, $zAxisRotation, $scaleDifference);
398
    }
399
400
    /**
401
     * Time-specific Coordinate Frame rotation (geocen)
402
     * Note the analogy with the Time-specific Position Vector method (code 1065) but beware of the differences!
403 36
     */
404
    public function timeSpecificCoordinateFrameRotation(
405
        Geocentric $to,
406
        Length $xAxisTranslation,
407
        Length $yAxisTranslation,
408
        Length $zAxisTranslation,
409
        Angle $xAxisRotation,
410
        Angle $yAxisRotation,
411
        Angle $zAxisRotation,
412
        Scale $scaleDifference,
413
        Time $transformationReferenceEpoch
414 36
    ): self {
415 9
        if ($this->epoch === null) {
416
            throw new InvalidCoordinateException(sprintf('This transformation is only valid for epoch %s, none given', $transformationReferenceEpoch->getValue()));
417
        }
418
419 27
        // Points use PHP DateTimes for ease of use, but transformations use decimal years...
420
        $pointEpoch = Year::fromDateTime($this->epoch ?? new DateTime());
421 27
422 9
        if (abs($pointEpoch->getValue() - $transformationReferenceEpoch->getValue()) > 0.001) {
423
            throw new InvalidCoordinateException(sprintf('This transformation is only valid for epoch %s, got %s', $transformationReferenceEpoch, $pointEpoch));
424
        }
425 18
426
        return $this->coordinateFrameRotation($to, $xAxisTranslation, $yAxisTranslation, $zAxisTranslation, $xAxisRotation, $yAxisRotation, $zAxisRotation, $scaleDifference);
427
    }
428
429
    /**
430
     * Time-specific Position Vector transform (geocen)
431
     * Note the analogy with the Time-specifc Coordinate Frame method (code 1066) but beware of the differences!
432 27
     */
433
    public function timeSpecificPositionVectorTransformation(
434
        Geocentric $to,
435
        Length $xAxisTranslation,
436
        Length $yAxisTranslation,
437
        Length $zAxisTranslation,
438
        Angle $xAxisRotation,
439
        Angle $yAxisRotation,
440
        Angle $zAxisRotation,
441
        Scale $scaleDifference,
442
        Time $transformationReferenceEpoch
443 27
    ): self {
444 9
        if ($this->epoch === null) {
445
            throw new InvalidCoordinateException(sprintf('This transformation is only valid for epoch %s, none given', $transformationReferenceEpoch->getValue()));
446
        }
447
448 18
        // Points use PHP DateTimes for ease of use, but transformations use decimal years...
449
        $pointEpoch = Year::fromDateTime($this->epoch);
450 18
451 9
        if (abs($pointEpoch->getValue() - $transformationReferenceEpoch->getValue()) > 0.001) {
452
            throw new InvalidCoordinateException(sprintf('This transformation is only valid for epoch %s, got %s', $transformationReferenceEpoch, $pointEpoch));
453
        }
454 9
455
        return $this->positionVectorTransformation($to, $xAxisTranslation, $yAxisTranslation, $zAxisTranslation, $xAxisRotation, $yAxisRotation, $zAxisRotation, $scaleDifference);
456
    }
457 18
458
    public function asGeographicValue(): GeographicValue
459 18
    {
460
        return (new GeocentricValue($this->x, $this->y, $this->z, $this->getCRS()->getDatum()))->asGeographicValue();
461
    }
462
}
463