Issues (86)

src/Point/VerticalPoint.php (1 issue)

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

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