Passed
Push — master ( fd93b5...48e916 )
by Doug
40:26 queued 29:39
created

VerticalPoint::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord;
10
11
use function abs;
12
use function cos;
13
use DateTime;
14
use DateTimeImmutable;
15
use DateTimeInterface;
16
use PHPCoord\CoordinateOperation\GeographicGeoidHeightGrid;
17
use PHPCoord\CoordinateReferenceSystem\Vertical;
18
use PHPCoord\Exception\InvalidCoordinateReferenceSystemException;
19
use PHPCoord\UnitOfMeasure\Angle\Angle;
20
use PHPCoord\UnitOfMeasure\Length\Length;
21
use PHPCoord\UnitOfMeasure\Length\Metre;
22
use function sin;
23
use function sqrt;
24
25
/**
26
 * Coordinate representing a vertical dimension.
27
 */
28
class VerticalPoint extends Point
29
{
30
    /**
31
     * Height.
32
     */
33
    protected Length $height;
34
35
    /**
36
     * Coordinate reference system.
37
     */
38
    protected Vertical $crs;
39
40
    /**
41
     * Coordinate epoch (date for which the specified coordinates represented this point).
42
     */
43
    protected ?DateTimeImmutable $epoch;
44
45
    /**
46
     * Constructor.
47
     * @param Length $height refer to CRS for preferred unit of measure, but any length unit accepted
48
     */
49 191
    protected function __construct(Length $height, Vertical $crs, ?DateTimeInterface $epoch = null)
50
    {
51 191
        $this->height = $height::convert($height, $crs->getCoordinateSystem()->getAxes()[0]->getUnitOfMeasureId());
52 191
        $this->crs = $crs;
53
54 191
        if ($epoch instanceof DateTime) {
55 9
            $epoch = DateTimeImmutable::createFromMutable($epoch);
56
        }
57 191
        $this->epoch = $epoch;
58 191
    }
59
60
    /**
61
     * Constructor.
62
     * @param Length $height refer to CRS for preferred unit of measure, but any length unit accepted
63
     */
64 191
    public static function create(Length $height, Vertical $crs, ?DateTimeInterface $epoch = null): self
65
    {
66 191
        return new static($height, $crs, $epoch);
67
    }
68
69 155
    public function getHeight(): Length
70
    {
71 155
        return $this->height;
72
    }
73
74 45
    public function getCRS(): Vertical
75
    {
76 45
        return $this->crs;
77
    }
78
79 27
    public function getCoordinateEpoch(): ?DateTimeImmutable
80
    {
81 27
        return $this->epoch;
82
    }
83
84 9
    public function calculateDistance(Point $to): Length
85
    {
86 9
        if ($to->getCRS()->getSRID() !== $this->crs->getSRID()) {
87
            throw new InvalidCoordinateReferenceSystemException('Can only calculate distances between two points in the same CRS');
88
        }
89
90
        /* @var self $to */
91 9
        return new Metre(abs($this->height->asMetres()->getValue() - $to->height->asMetres()->getValue()));
92
    }
93
94 54
    public function __toString(): string
95
    {
96 54
        return "({$this->height})";
97
    }
98
99
    /**
100
     * Vertical Offset
101
     * This transformation allows calculation of height (or depth) in the target system by adding the parameter value
102
     * to the height (or depth)-value of the point in the source system.
103
     */
104 9
    public function offset(
105
        Vertical $to,
106
        Length $verticalOffset
107
    ): self {
108 9
        return static::create($this->height->add($verticalOffset), $to);
109
    }
110
111
    /**
112
     * Vertical Offset and Slope
113
     * This transformation allows calculation of height in the target system by applying the parameter values to the
114
     * height value of the point in the source system.
115
     */
116 18
    public function offsetAndSlope(
117
        Vertical $to,
118
        Angle $ordinate1OfEvaluationPoint,
119
        Angle $ordinate2OfEvaluationPoint,
120
        Length $verticalOffset,
121
        Angle $inclinationInLatitude,
122
        Angle $inclinationInLongitude,
123
        string $EPSGCodeForHorizontalCRS,
0 ignored issues
show
Unused Code introduced by
The parameter $EPSGCodeForHorizontalCRS is not used and could be removed. ( Ignorable by Annotation )

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

123
        /** @scrutinizer ignore-unused */ string $EPSGCodeForHorizontalCRS,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
        GeographicPoint $horizontalPoint
125
    ): self {
126 18
        $ellipsoid = $horizontalPoint->getCRS()->getDatum()->getEllipsoid();
127 18
        $latitude = $horizontalPoint->getLatitude()->asRadians()->getValue();
128 18
        $longitude = $horizontalPoint->getLongitude()->asRadians()->getValue();
129 18
        $latitudeOrigin = $ordinate1OfEvaluationPoint->asRadians()->getValue();
130 18
        $longitudeOrigin = $ordinate2OfEvaluationPoint->asRadians()->getValue();
131 18
        $a = $ellipsoid->getSemiMajorAxis()->asMetres()->getValue();
132 18
        $e2 = $ellipsoid->getEccentricitySquared();
133
134 18
        $rhoOrigin = $a * (1 - $e2) / (1 - $e2 * sin($latitudeOrigin) ** 2) ** 1.5;
135 18
        $nuOrigin = $a / sqrt(1 - $e2 * (sin($latitudeOrigin) ** 2));
136
137 18
        $latitudeTerm = new Metre($inclinationInLatitude->asRadians()->getValue() * $rhoOrigin * ($latitude - $latitudeOrigin));
138 18
        $longitudeTerm = new Metre($inclinationInLongitude->asRadians()->getValue() * $nuOrigin * ($longitude - $longitudeOrigin) * cos($latitude));
139 18
        $newVerticalHeight = $this->getHeight()->add($verticalOffset)->add($latitudeTerm)->add($longitudeTerm);
140
141 18
        return self::create($newVerticalHeight, $to);
142
    }
143
144
    /**
145
     * Height Depth Reversal.
146
     */
147 9
    public function heightDepthReversal(
148
        Vertical $to
149
    ): self {
150 9
        return static::create($this->height->multiply(-1), $to);
151
    }
152
153
    /**
154
     * Change of Vertical Unit.
155
     */
156 9
    public function changeOfVerticalUnit(
157
        Vertical $to
158
    ): self {
159
        // units are auto-converted, don't need to use the supplied param
160 9
        return static::create($this->height, $to, $this->epoch);
161
    }
162
163
    /**
164
     * Zero-tide height to mean-tide height (EVRF2019)
165
     * The offset of -0.08593 is applied to force EVRF2019 mean-tide height to be equal to EVRF2019 height at the
166
     * EVRF2019 nominal origin at Amsterdams Peil.
167
     */
168 18
    public function zeroTideHeightToMeanTideHeightEVRF2019(
169
        Vertical $to,
170
        bool $inReverse,
171
        GeographicPoint $horizontalPoint
172
    ): self {
173 18
        $latitude = $horizontalPoint->getLatitude()->asRadians()->getValue();
174 18
        $delta = new Metre((0.29541 * sin($latitude) ** 2 + 0.00042 * sin($latitude) ** 4 - 0.0994) - 0.08593);
175
176 18
        if ($inReverse) {
177 9
            $delta = $delta->multiply(-1);
178
        }
179
180 18
        return static::create($this->height->add($delta), $to);
181
    }
182
183
    /**
184
     * Vertical Offset by Grid Interpolation.
185
     */
186 2
    public function offsetFromGrid(
187
        Vertical $to,
188
        GeographicGeoidHeightGrid $offsetsFile,
189
        bool $inReverse,
190
        GeographicPoint $horizontalPoint
191
    ): self {
192 2
        $offset = $offsetsFile->getHeightAdjustment($horizontalPoint);
193
194 2
        if ($inReverse) {
195 1
            $offset = $offset->multiply(-1);
196
        }
197
198 2
        return static::create($this->height->add($offset), $to);
199
    }
200
}
201