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
|
|||
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 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.